3

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)。私のコードにエラーがありますか、それとも asyncore/select() で AF_UNIX ソケットを管理できませんか?

4

2 に答える 2

5

他の回答が指摘しているように、データグラムを送信するときは、受信者を指定する必要があります。現状では、testselectクラスはサーバーというよりクライアントのように見えます。

これらのいくつかをasyncore examples確認して、コピーできるサーバー パターンを見つけてください。このTimeChannel例は、あなたが望むものに近いものです。バインド アドレスのソケット パスを変更socket.AF_INETsocket.AF_UNIXて使用し、UNIX ドメイン ソケットを使用するようにします。


socket.SOCK_DGRAM通常、UDP INET ソケットの作成を示す設定です。Unix ドメイン ソケットは、IPC の一種です。socket.SOCK_STREAM、 call self.listen([backlog])、 implementhandle_accept()などに変更する必要があります。

AF_UNIX で SOCK_DGRAM を使用するつもりだった場合、サーバーが終了する理由は、サーバーが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)
于 2011-05-13T16:42:05.430 に答える
1

あなたの難しさは、SOCK_DGRAMを使用しているという事実に要約することができます。私の知る限り、基本的に、非同期(norecvfromまたはsendto)を使用してSOCK_DGRAMソケットを効果的に処理することはできません。さらに、socatにはSOCK_DGRAMUNIXドメインソケットを操作する方法がないようです。

SOCK_DGRAMソケットには接続の実際の概念がないため、select呼び出しで常に書き込み可能として登録されます。ただし、実際に実行するwriteと、宛先アドレスを指定していないため失敗します。

もう1つの答えは用語が間違っていますが、基本的には正しいです。ここではSOCK_STREAMソケットを使用する必要があります。

于 2011-05-13T16:55:02.890 に答える