3

有两个文件: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.pyhandle_closed中的函数执行了两次?

  2. 为什么server.pyhandle_reading中的函数没有执行?client.py发送了 message( " Hello Client"),但是为什么服务端收不到呢?

  3. 为什么server.pyhandle_closed中的函数没有执行?当客户端退出时,我想在server.py中执行一些代码,但似乎它在server.py中没有任何作用?handle_closed

4

3 回答 3

9

异步谈话

handle_read()in server.py 永远不会被调用。

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

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

阅读 asyncore 模块和在其他问题中的回答。

服务器

就像我说的,你需要在 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()

请注意,在收到 null 时读取不需要手动关闭套接字 -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库会让你感兴趣!

于 2013-08-03T21:01:22.920 回答
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()
于 2013-09-13T20:45:58.283 回答
0

要完成这项handle_read()工作,您应该定义readable()函数。此函数必须返回TrueFalse。我认为将此功能添加到您的代码将解决问题:

def readable(self):
    return True

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

于 2015-07-28T01:50:45.647 回答