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