2011-05-13 48 views
3

我有一些使用AF_UNIX套接字asyncore的問題。此代碼蟒蛇asyncore與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 
$ 

它立刻退出,而不會等待讀取和寫入。如果我改變代碼強制寫()方法返回總是False,它正確地等待輸入,我可以用socat這樣

$ socat readline UNIX:/tmp/mysocket 

但僅讀(寫溝通邏輯不工作,因爲可寫的()返回False)。我的代碼中是否有錯誤,或者我無法使用asyncore/select()管理AF_UNIX套接字?

+0

這是一個非常有趣的難題,你有。 – Omnifarious 2011-05-13 16:34:52

回答

5

注意正如另一個答案指出,當你發送一個數據報,你需要指定接收器。就目前來看,你的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_connecthandle_read設置緩衝區:

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

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

現在,當您啓動服務器時,它會等待,直到它從接收到數據包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 2011-05-13 16:56:53

+0

是的,當我指DGRAM時說UDP。不應該寫得比我想象的要快。 – samplebias 2011-05-13 17:06:17

+0

TimeServer示例像魅力一樣工作。謝謝。 – Emilio 2011-05-13 17:30:23

1

你的困難可以歸結到你使用SOCK_DGRAM的事實。從我所知道的情況來看,你基本上無法有效地處理異步(不是recvfromsendto)的SOCK_DGRAM套接字。此外,socat似乎沒有辦法使用SOCK_DGRAM UNIX域套接字。

SOCK_DGRAM套接字沒有真正的連接概念,所以它們將始終在選擇調用中註冊爲可寫。但是當你真的做了write它會失敗,因爲你沒有提供目的地址。

其他答案有術語錯誤,但基本正確。您需要在這裏使用SOCK_STREAM套接字。