2011-05-13 4 views
3

AF_UNIX 소켓과 함께 asyncore를 사용할 때 몇 가지 문제가 있습니다. 이 코드 AF_UNIX 소켓과 함께 작동하는 파이썬 asyncore 문제

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() 

내가 코드 그것은 immediatly 종료되고 읽기 대기 및 기록하지 않습니다

$ python select_prova.py 
writable 
handle_connect 
handle_write 
handle_close 
$ 

을 실행하면

. 난 항상 False을 반환 쓰기() 메소드를 강제로 코드를 변경하면 입력을 제대로 기다려 난 (쓰기 읽기 전용이

$ socat readline UNIX:/tmp/mysocket 

그러나 같은 socat와 통신 할 수있는 논리적으로하지 않습니다 작동하기 때문에 쓰기() False을 반환). 내 코드에 오류가 있습니까? 아니면 asyncore/select()를 사용하여 AF_UNIX 소켓을 관리 할 수 ​​있습니까?

+0

이는 데있어 정말 흥미있는 어려움이다. – Omnifarious

답변

5

참고 다른 답변에서 지적한 것처럼 데이터 그램을 보낼 때 수신기를 지정해야합니다. 그대로 서면 testselect 클래스는 서버가 아닌 클라이언트처럼 보입니다.

asyncore examples 중 일부를 검토하여 복사 할 수있는 서버 패턴을 찾으십시오. TimeChannel 예제가 원하는 것입니다. socket.AF_INETsocket.AF_UNIX으로 변경하고 바인드 주소에 소켓 경로를 사용하여 UNIX 도메인 소켓을 사용하십시오.


당신은 일반적으로 UDP INET 소켓의 생성을 나타냅니다 socket.SOCK_DGRAM을 설정하고 있습니다. Unix 도메인 소켓은 IPC의 한 형태입니다. 당신은 등, handle_accept() 구현, self.listen([backlog]) 전화, socket.SOCK_STREAM로 변경해야

당신은 AF_UNIX에 handle_write의 원인이 즉시 시작할 것 같은 writable를 나타내는 것을 서버가 종료되는 이유와 SOCK_DGRAM을 사용하려는 않은 경우 즉시 'buffer'을 포함하는 패킷을 보내십시오. 당신이 당신의 서버를 시작할 때부터 패킷을 수신 할 때까지 지금은 기다릴 것이다

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

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

을 : 당신이 회신하기 전에 패킷을받은 때까지 서버가 대기 할 경우

handle_connect 또는 handle_read에 버퍼를 설정 socat. 난 당신이 indend 더처럼 작동하도록 예를 다시 한


은 :

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) 
+0

여기에는 TCP 또는 UDP가 없으며 Zuul 만 있습니다. 오류 ... TCP 및 UDP는 IP 프로토콜 위에 있습니다. AF_UNIX 소켓은 IP를 말하지 않습니다. 그들은 파이프에 더 가깝습니다. – Omnifarious

+0

그래, DGRAM을 의미 할 때 UDP라고 말했어. 내가 생각하는 것보다 빨리 쓰지 말아야한다. – samplebias

+0

TimeServer 예제는 매력처럼 작동합니다. 고맙습니다. – Emilio

1

귀하의 어려움은 당신이 SOCK_DGRAM을 사용하고있는 사실로 요약 될 수있다. 알 수 있듯이 기본적으로 asyncore (no recvfrom 또는 sendto)를 사용하여 SOCK_DGRAM 소켓을 효과적으로 처리 할 수 ​​없습니다. 또한 socat은 SOCK_DGRAM UNIX 도메인 소켓을 사용하는 방법이없는 것처럼 보입니다.

SOCK_DGRAM 소켓에는 연결에 대한 실제 개념이 없으므로 항상 선택 호출에 쓰기 가능으로 등록됩니다. 그러나 실제로 write을 수행하면 대상 주소를 제공하지 않아 실패합니다.

다른 답변에는 잘못된 용어가 있지만 기본적으로 정확합니다. 여기에 SOCK_STREAM 소켓을 사용해야합니다.

관련 문제