سؤال

أواجه بعض المشكلات في استخدام غير المتزامن مع مآخذ توصيل AF_UNIX.هذا الرمز

import asyncore, socket, os
class testselect(asyncore.dispatcher):

    path = '/tmp/mysocket'

    def __init__(self):

        asyncore.dispatcher.__init__(self)

        self.create_socket(socket.AF_UNIX, socket.SOCK_DGRAM)
        self.bind(self.path)
        self.buffer = 'buffer'

    def handle_connect(self):

        print 'handle_connect'
        pass

    def handle_close(self):
        print 'handle_close'
        if os.path.exists(self.path)       
             os.remove(self.path)
        self.close()

    def handle_read(self):
        print 'handle_read'
        print self.recv(8192)

    def writable(self):
        print 'writable'
        return (len(self.buffer) > 0)

    def handle_write(self):
        print 'handle_write'
        sent = self.send(self.buffer)
        self.buffer = self.buffer[sent:]


    client = testselect()
    asyncore.loop()

إذا قمت بتنفيذ الكود

 $ python select_prova.py
 writable
 handle_connect
 handle_write
 handle_close
 $  

يتوقف على الفور، ولا ينتظر القراءة والكتابة.إذا قمت بتغيير الكود لإجبار طريقة writable() على العودة دائمًا False, ، فإنه ينتظر الإدخال بشكل صحيح ويمكنني التواصل مع socat بهذه الطريقة

 $ socat readline UNIX:/tmp/mysocket

ولكن فقط للقراءة (الكتابة المنطقية لا تعمل لأن writable() تُرجع False).هل يوجد خطأ في الكود الخاص بي أو لا أستطيع إدارة مآخذ توصيل AF_UNIX باستخدام asyncore/select() ؟

هل كانت مفيدة؟

المحلول

ملحوظة كما تشير الإجابة الأخرى، عندما ترسل مخطط بيانات، فإنك تحتاج إلى تحديد جهاز الاستقبال.كما هو الحال، الخاص بك testselect يبدو الفصل وكأنه عميل أكثر من الخادم.

مراجعة بعض هذه asyncore examples للعثور على نمط الخادم الذي يمكنك نسخه.ال TimeChannel المثال هو أقرب إلى ما تريد - التغيير socket.AF_INET ل socket.AF_UNIX واستخدم مسار مأخذ توصيل لعنوان الربط ليستخدم مأخذ توصيل مجال UNIX.


أنت تقوم بالإعداد socket.SOCK_DGRAM والذي يشير عادةً إلى إنشاء مقبس UDP INET.مآخذ مجال Unix هي شكل من أشكال IPC.يجب عليك تغييره إلى socket.SOCK_STREAM, ، يتصل self.listen([backlog]), ، ينفذ handle_accept(), ، إلخ.

إذا كنت تنوي استخدام SOCK_DGRAM مع AF_UNIX، فإن سبب خروج الخادم الخاص بك هو أنه يشير إلى writable بمجرد أن تبدأ، وهو ما يسبب handle_write لتشغيل، وإرسال الحزمة التي تحتوي على 'buffer' في الحال.

إذا كنت تريد أن ينتظر خادمك حتى يتلقى الحزمة قبل الرد، فقم بتعيين المخزن المؤقت handle_connect أو handle_read:

    def __init__(self):
        ...
        self.buffer = ''

    def handle_connect(self):
        self.buffer = 'buffer'

الآن، عند بدء تشغيل الخادم الخاص بك، سينتظر حتى يتلقى حزمة منه socat.


لقد قمت بإعادة كتابة المثال الخاص بك للعمل بطريقة تشبه ما تقصده:

import asyncore, socket, os

class testselect(asyncore.dispatcher):

    path = '/tmp/mysocket'

    def __init__(self):
        asyncore.dispatcher.__init__(self)
        self.create_socket(socket.AF_UNIX, socket.SOCK_STREAM)
        self.set_reuse_addr()
        self.bind(self.path)
        self.listen(5)

    def handle_accept(self):
        client = self.accept()
        if client is None:
            pass
        else:
            handler = testhandler(*client)

class testhandler(asyncore.dispatcher_with_send):

    def __init__(self, sock, addr):
        asyncore.dispatcher_with_send.__init__(self, sock)
        self.addr = addr
        self.buffer = 'greetings'

    def handle_read(self):
        print self.recv(8192)

    def writable(self):
        return (len(self.buffer) > 0)

    def handle_write(self):
        self.send(self.buffer)
        self.buffer = ''

    def handle_close(self):
        self.close()

server = testselect()
try:
    asyncore.loop()
finally:
    if os.path.exists(testselect.path):
        os.unlink(testselect.path)

نصائح أخرى

يمكن تلخيص الصعوبة التي تواجهها في حقيقة أنك تستخدم SOCK_DGRAM.مما يمكنني قوله، لا يمكنك بشكل أساسي التعامل مع مآخذ SOCK_DGRAM بشكل فعال مع غير متزامن (رقم recvfrom أو sendto).بالإضافة إلى ذلك، لا يبدو أن لدى socat طريقة للعمل مع مآخذ توصيل مجال SOCK_DGRAM UNIX.

لا تحتوي مآخذ SOCK_DGRAM على فكرة حقيقية عن الاتصال، لذلك سيتم تسجيلها دائمًا على أنها قابلة للكتابة في مكالمة محددة.ولكن عندما تفعل ذلك بالفعل write ستفشل لأنك لا تقدم عنوان الوجهة.

الإجابة الأخرى لها مصطلحات خاطئة، ولكنها صحيحة في الأساس.تحتاج إلى استخدام مقبس SOCK_STREAM هنا.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top