有两个文件:server.py和client.py,都是在asyncore.dispatcher的帮助下编写的
Server.py
import asyncore, socket
class Server(asyncore.dispatcher):
def __init__(self, host, port):
asyncore.dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.bind(('', port))
self.listen(1)
print "Waiting for connection..."
def handle_accept(self):
socket, address = self.accept()
print 'Connection by', address
socket.send("Hello Server")
def handle_read(self):
print "Reading..."
out_buffer = self.recv(1024)
if not out_buffer:
self.close()
print out_buffer
def handle_closed(self):
print "Server: Connection Closed"
self.close()
s = Server('0.0.0.0', 5007)
asyncore.loop()
Client.py
import asyncore, socket
class Client(asyncore.dispatcher):
def __init__(self, host, port):
asyncore.dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.connect((host, port))
print "Client Start..."
def handle_close(self):
print "Client: Connection Closed"
self.close()
def handle_read(self):
data = self.recv(1024)
if data:
print "Received ", data
self.send("Hello Client")
c = Client('127.0.0.1', 5007)
asyncore.loop()
结果:
执行server.py
:
Waiting for connection...
然后client.py
:
Client Start...
Received Hello Server
Client: Connection Closed
Client: Connection Closed
最后,client.py退出,并且在server.py的输出窗口中显示了另一行,服务器一直在运行:
Connection by ('127.0.0.1', 58197)
有些事我无法理解:
为什么 client.py 中的函数handle_closed
执行了两次?
为什么 server.py 中的功能handle_reading
未执行? client.py 已发送消息(“Hello Client”),但为什么服务器无法接收消息?
为什么 server.py 中的功能handle_closed
未执行?我希望在客户端退出时在 server.py 中执行一些代码,但似乎无法在 中执行handle_closed
操作server.py ?
答案 0 :(得分:9)
永远不会调用server.py中的handle_read()
。
但为什么?!这是一个服务器类......
是的,但是Server
类使用其套接字来监听任何未建立的连接。对它的任何读取都转到handle_accept()
,其中实际的通道套接字(连接到某个端点)应该被赋予某个dispatcher
的新实例 - 继承类(最好)。在Server
的{{1}}方法中,handle_accept()
获取的套接字是本地的,因此在退出此函数时被删除,因此:接受新连接,发送文本并在该套接字立即被杀死之后
在asyncore模块和my answer上阅读其他问题。
你需要像我说的那样,在server.py中为连接创建新类:
accept()
请注意,当收到null时,读取不需要手动关闭套接字 - class ClientHandler(asyncore.dispatcher):
def handle_read(self):
data = self.recv(1024)
if not data:
return
print "Received:", data
def handle_close(self):
print "Server: Connection Closed"
self.close()
负责正确关闭连接。
然后,当你建立连接时,你必须在asyncore
中实例化它:
Server
您在 def handle_accept(self):
...
ClientHandler(socket)
中也犯了拼写错误 - 方法的正确名称为Server
。虽然它没用。与客户端连接相关的所有内容都在handle_close
。
在client.py中,您只需修改ClientHandler
:
handle_read()
更改为:
if data:
print "Received ", data
为什么呢?如果没有这个 if not data:
return
print "Received ", data
,即使套接字实际关闭也会被调用,导致send()
被handle_close()
第二次调用。就像我说的那样 - asyncore
负责这个。
现在,您可以为连接编写更复杂的服务器端类。您还可以了解操作系统级套接字的工作原理,这样您就不会遇到麻烦。
asyncore
本身是套接字的一个非常好的包装器,但是如果你想在某些事件驱动的环境中做更高级别的事情,比如HTTP或SMTP处理,那么Twisted库会引起你的兴趣!
答案 1 :(得分:1)
我今天遇到了类似的问题。 handle_close类运行两次因为read函数返回一组空白数据然后导致handle_write触发,当handle_write看到空白数据时,它会再次关闭请求。
如上所述,您需要将handle_read和handle_write函数分隔为单独的“处理程序”类。然后,只需检查缓冲区是否有空白数据,如果数据为空白则返回。
在下面的代码中,我将添加每个请求的开始长度。所以,我先把它拉出来以获得缓冲区大小。如果为空,则该函数返回
class Handler(asyncore.dispatcher_with_send):
def __init__(self, conn_sock, client_address, server):
self.SERVER = server
self.CA = client_address
self.DATA = ''
self.out_buffer = ''
self.BUFFER = 1024
self.is_writable = False
# Create with an already provided socket
asyncore.dispatcher.__init__(self, conn_sock)
def readable(self):
return True
def writable(self):
return self.is_writable
def handle_read(self):
buffer = str(self.recv(8))
if buffer != '': size = int(buffer)
else: return
data = self.recv(size)
if data:
self.DATA += data
self.is_writable = True
def handle_write(self):
if self.DATA:
self.RESPONSE = processRequest(self.DATA)
dlen = "%08d" % (len(self.RESPONSE)+8,)
sent = self.sendall(dlen+self.RESPONSE)
self.DATA = self.RESPONSE[sent:]
self.RESPONSE = ''
if len(self.DATA) == 0:
self.is_writable = False
def handle_close(self):
self.close()
class Server(asyncore.dispatcher):
FAMILY = socket.AF_INET
TYPE = socket.SOCK_STREAM
def __init__(self):
self.HANDLER = Handler
#check for a specified host
self.HOST = "localhost"
#check for a specified port
self.PORT = 50007
#check the queue size
self.QUEUE = 5
#set the reuse var
self.REUSE = False
#dispatch
self.dispatch()
def dispatch(self):
#init the dispatcher
asyncore.dispatcher.__init__(self)
self.create_socket(self.FAMILY, self.TYPE)
#check for address reuse
if self.REUSE: self.set_reuse_addr()
#bind and activate the server
self.server_bind()
self.server_activate()
def server_bind(self):
self.bind((self.HOST, self.PORT))
def server_activate(self):
self.listen(self.QUEUE)
def fileno(self):
return self.socket.fileno()
def serve(self):
asyncore.loop()
def handle_accept(self):
(conn_sock, client_address) = self.accept()
if self.verify_request(conn_sock, client_address):
self.process_request(conn_sock, client_address)
def verify_request(self, conn_sock, client_address):
return True
def process_request(self, conn_sock, client_address):
self.HANDLER(conn_sock, client_address, self.LOG, self.LOGFILE, self)
def handle_close(self):
self.close()
if __name__ == '__main__':
server = Server()
server.serve()
答案 2 :(得分:0)
要使handle_read()
有效,您应该定义readable()
函数。此函数必须返回True
或False
。我认为将此函数添加到您的代码将解决问题:
def readable(self):
return True
有关一些示例和更多详细信息,请访问此链接:https://parijatmishra.wordpress.com/2008/01/04/writing-a-server-with-pythons-asyncore-module/