python中的asyncore.dispatcher:handle_何时关闭并执行handle_read?

2024-05-15 02:10:56 发布

您现在位置:Python中文网/ 问答频道 /正文

有两个文件:server.py和client.py,都是在asyncore.dispatcher的帮助下编写的

服务器.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()

客户端.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中执行一些代码,但它似乎与在server.py中执行无关?


Tags: pyselfclientserverinitportdefsocket
3条回答

我今天也有类似的问题。HealLeHelp类运行两次,因为Read函数返回一组空白数据,然后导致HeleLyWrad触发,当HydLyWrad看到空白数据时,它第二次关闭请求。

如上所述,您需要将handle_read和handle_write函数分离为一个单独的“handler”类。然后,检查缓冲区中是否有空白数据,如果数据为空白,则返回。

在下面的代码中,我将添加每个请求的请求长度。所以,我先拉这个来得到缓冲区的大小。如果为空,则函数返回

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

异步通话

永远不会调用server.py中的handle_read()

但为什么?!这是一个服务器类。。。

是的,但是Server类使用它的套接字来监听任何未建立的连接。它上的任何读取都会转到handle_accept(),在这里,实际的通道套接字(连接到某个端点)应该被赋予某些dispatcher继承类的新实例(最好)。在Serverhandle_accept()方法中,由accept()获得的套接字是本地的,因此在退出此函数时将其删除,因此:接受新连接,发送文本,然后立即终止套接字。

阅读异步模块和my answer中的其他问题。

服务器

如我所说,您需要在server.py中为连接创建新类:

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。尽管这没用。与客户端连接相关的所有内容都在ClientHandler中。

客户

在client.py中,只需修改handle_read()

    if data:
        print "Received ", data

更改为:

    if not data:
        return
    print "Received ", data

为什么?如果没有这个,send()将被调用,即使套接字实际上是关闭的,这将导致handle_close()asyncore第二次调用。就像我说的-asyncore处理这个。

注释

现在您可以为连接编写更复杂的服务器端类。您还可以学习操作系统级套接字的工作方式,这样就不会遇到麻烦。

asyncore本身是一个很好的套接字包装器,但是如果您想在某些事件驱动环境中执行更高级别的操作,比如HTTP或SMTP处理,那么Twisted库会让您感兴趣!

要使handle_read()工作,您应该定义readable()函数。此函数必须返回TrueFalse。我认为将此函数添加到代码中可以解决问题:

def readable(self):
    return True

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

相关问题 更多 >

    热门问题