python中的asyncore.dispatcher:handle_closed和handle_read何时执行?

时间:2013-07-18 09:51:34

标签: python sockets asyncore

有两个文件: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)

有些事我无法理解:

  1. 为什么 client.py 中的函数handle_closed执行了两次?

  2. 为什么 server.py 中的功能handle_reading未执行? client.py 已发送消息(“Hello Client”),但为什么服务器无法接收消息?

  3. 为什么 server.py 中的功能handle_closed未执行?我希望在客户端退出时在 server.py 中执行一些代码,但似乎无法在 中执行handle_closed操作server.py

3 个答案:

答案 0 :(得分:9)

Asyncore谈话

永远不会调用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()函数。此函数必须返回TrueFalse。我认为将此函数添加到您的代码将解决问题:

def readable(self):
    return True

有关一些示例和更多详细信息,请访问此链接:https://parijatmishra.wordpress.com/2008/01/04/writing-a-server-with-pythons-asyncore-module/