2013-01-15 22 views
4

python 2.6 Windows 7构建异步套接字教程:如何连接到python中的监听套接字?

我想尽可能简单地编写一个如何编写合作性多任务程序的教程。作为一个示例应用程序,我用python的asyncore后端编写了一个聊天服务器。我认为这将成为社区的宝贵资源。但是,我还没有得到它的工作,因此这篇文章。

结构如下。 ChatServer的一个实例在远程计算机上运行。它的套接字在REMOTE_PORT上进行监听。当它检测到传入连接时,它会生成一个ChatHandler实例来调解与该连接的通信。现在,这是什么关系?在用户的本地机器上,我们运行一个ChatDaemon实例。这个人听LOCAL_PORT。当您连接到他这个样子

import socket 
s = socket.socket() 
s.connect(('localhost',LOCAL_PORT)) 

他检测连接,并产生两个东西,一个LocalListener和连接。连接连接到服务器,回答我们上面的问题。 LocalListener只是等待来自用户的数据。如果发送数据

s.send("Hello, world!") 

的LocalListener它捡起,并且给它的连接,然后将其发送到的ChatServer。然后,服务器将数据放入每个ChatHandler的缓冲区中发送给所有连接的客户端。当连接接收到这些数据时,它将它传递给守护进程,守护进程将其打印到屏幕上。 (守护层似乎过于复杂,但没有它你必须做其他复杂的事情,以防止在异步的select()循环中的热循环,同时保持用户发送数据低的延迟。我不想让道路)。

问题是,与守护进程的连接似乎没有进行。我的具体步骤是

在一个蟒蛇会议

d = ChatDaemon('localhost') 
d.start() 

当我做到这一点我看到消息“聊天守护结合的‘localhost:7668’。如预期

在另一个Python会话

import socket 
s = socket.socket() 
s.connect(('localhost',7668)) 

当我这样做,我没有看到“有了新的本地连接”的印刷线。

我编辑了我的etc/hosts文件,将'localhost'映射到127.0.0.1,并安装了Microsoft Loopback适配器。

编辑:我发现并解决了这个问题。下面的代码现在应该可以接受为使用asyncore的非常简单的聊天实现。

这里是源

import asyncore 
import socket 
import sys 

LOCAL_HOST = 'localhost' 
LOCAL_PORT = 7668 
REMOTE_HOST = 'localhost' 
REMOTE_PORT = 7667 

class LocalListener(asyncore.dispatcher): 
    """Receive data from user, putting into cxn's buffer""" 
    def __init__(self, sock, cxn): 
     self.cxn = cxn 
     asyncore.dispatcher.__init__(self, sock) 

    def writable(self): 
     return False 

    def readable(self): 
     return True 

    def handle_read(self): 
     data = self.recv(4096) 
     if data: 
      self.cxn.buf = self.cxn.buf + data 

class Connection(asyncore.dispatcher): 
    """Mediates between user and server""" 
    def __init__(self, host, port, master): 
     asyncore.dispatcher.__init__(self) 
     self.create_socket(socket.AF_INET, socket.SOCK_STREAM) 
     self.connect((host,port)) 
     self.buf="" 

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

    def readable(self): 
     return True 

    def handle_read(self): 
     data = self.recv(4096) 
     if data: 
      self.master.newMessage(data) 

    def handle_write(self): 
     sent = self.send(self.buf) 
     self.buf = self.buf[sent:] 

class ChatDaemon(asyncore.dispatcher): 
    """Listen for local connections and dispatch in/out data""" 
    ADDRESS_FAMILY = socket.AF_INET 
    SOCKET_TYPE = socket.SOCK_STREAM 
    def __init__(self, remoteHost, remotePort=REMOTE_PORT, 
       localHost=LOCAL_HOST, localPort=LOCAL_PORT): 
     self.remoteHost = remoteHost 
     self.remotePort = remotePort 
     self.localHost = localHost 
     self.localPort = localPort 
     self.buffer = "" 
     asyncore.dispatcher.__init__(self) 

    def writable(self): 
     return False 

    def readable(self): 
     return True 

    def newMessage(self, data): 
     print data 

    def start(self): 
     """Listen for user connection on local port""" 
     self.create_socket(self.ADDRESS_FAMILY, self.SOCKET_TYPE) 
     print("Chat deamon binding to '%s': %s"%(self.localHost,self.localPort)) 
     self.bind((self.localHost,self.localPort)) 
     self.listen(1) 
     asyncore.loop() 

    def handle_accept(self): 
     """Spawn local reader and remote reader/writer""" 
     print "Got new local connection" 
     (connSock, localAddress) = self.accept() 
     print("New connection address is %s"%localAddress) 
     #Make a server connection 
     cxn = Connection(self.remoteHost, self.remotePort, self) 
     #Connect to local user 
     LocalListener(connSock, cxn) 

### SERVER ### 

class ChatHandler(asyncore.dispatcher): 
    def __init__(self, sock, map, server): 
     self.server = server 
     self.buffer = '' 
     asyncore.dispatcher.__init__(self, sock, map) 

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

    def readable(self): 
     return True 

    def handle_read(self): 
     """Notify server of any new incoming data""" 
     data = self.recv(4096) 
     if data: 
      self.server.newMessage(data, self) 

    def handle_write(self): 
     """send some amount of buffer""" 
     sent = self.send(self.buffer) 
     self.buffer = self.buffer[sent:] 

class ChatServer(asyncore.dispatcher): 
    """Receive and forward chat messages 

    When a new connection is made we spawn a dispatcher for that 
    connection. 
    """ 
    ADDRESS_FAMILY = socket.AF_INET 
    SOCKET_TYPE = socket.SOCK_STREAM 
    def __init__(self, host=REMOTE_HOST, port=REMOTE_PORT): 
     self.map = {} 
     self.address = (host,port) 
     self.clients = [] 
     asyncore.dispatcher.__init__(self, map=self.map) 

    def serve(self): 
     """Bind to socket and start asynchronous loop""" 
     self.create_socket(self.ADDRESS_FAMILY, self.SOCKET_TYPE) 
     self.bind(self.address) 
     self.listen(1) 
     asyncore.loop(map=self.map) 

    def writable(self): 
     return False 

    def readable(self): 
     return True 

    def newMessage(self, data, fromWho): 
     """Put data in all clients' buffers""" 
     for client in self.clients: 
      client.buf = client.buf + data 

    def handle_accept(self): 
     """Deal with newly accepted connection""" 
     print 'got new connection' 
     (connSock, clientAddress) = self.accept() 
     self.clients.append(ChatHandler(connSock, self.map, self)) 

回答

0

的问题是,在ChatDaemon我忘记了“回归”的关键字,可读可写