【问题标题】:python asyncore server send data to only one sockpython asyncore服务器仅将数据发送到一只袜子
【发布时间】:2013-07-31 02:07:38
【问题描述】:

我必须只向连接发送数据,我可以这样做吗?

服务器:

import asyncore, socket, threading

class EchoHandler(asyncore.dispatcher_with_send):
    def __init__(self,sock):
        asyncore.dispatcher.__init__(self,sock=sock);
        self.out_buffer = ''

    def handle_read(self):
        datos = self.recv(1024);
        if datos:
            print(datos);
            self.sock[0].send("signal");

class Server(asyncore.dispatcher):

    def __init__(self,host='',port=6666):
        asyncore.dispatcher.__init__(self);
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM);
        self.set_reuse_addr();
        self.bind((host,port));
        self.listen(1);

    def handle_accept(self):
        self.sock,self.addr = self.accept();
        if self.addr:
            print self.addr[0];
        handler = EchoHandler(self.sock);

    def handle_close(self):
        self.close();     

cliente = Server();
asyncore.loop()

这一行是一个失败的例子,但我想将数据发送到零袜子:

self.sock[0].send("probando");

例如,如果我有 5 个套接字,请选择向谁发送数据

【问题讨论】:

    标签: python sockets send asyncore


    【解决方案1】:

    说明

    您尝试从列表中获取 sock 并执行其发送方法。这会导致错误,因为EchoHandler 既没有 sock 属性也不是套接字列表。正确的方法是获取您想要的EchoHandler 实例(基于,例如IP 地址,或由某些用户定义的协议分配的插槽),然后使用它的发送方法 - 在这里(使用dispatcher_with_send)它也更好使用特殊缓冲区而不是发送。

    EchoHandler 实例在每次接受连接时创建 - 从那时起,它是一个已建立的通道,用于与给定主机通信。 Server 监听任何未建立的连接,而EchoHandlers 使用袜子(由handle_accept 中的Server 提供)用于已建立的连接,因此EchoHandler 实例与连接一样多。

    解决方案

    您需要创建一些连接列表(EchoHandler 实例;我们将使用缓冲区,而不是直接使用套接字的 send())并让他们有机会在关闭时删除他们的条目:

    class Server(asyncore.dispatcher):
        def __init__(self, host='', port=6666):
            ...
            self.connections = []
    
        def handle_accept(self):
            ...
            handler = EchoHandler(self.sock, self);
            self.connections.append(self.sock)
    
        ...
    
        def remove_channel(self, sock):
            if sock in self.connections:
                self.connections.remove(sock)
    
    class EchoHandler(asyncore.dispatcher_with_send):
        def __init__(self, sock, server):
            ...
            self.server = server
    
        def handle_read(self):
            datos = self.recv(1024);
            if datos:
                print(datos);
                self.out_buffer += 'I echo you: ' + datos
    
        def handle_close(self):
            self.server.remove_channel(self)
            self.close()
    

    EchoHandler 现在知道服务器实例并且可以从列表中删除它的套接字。这个回显示例现在功能齐全,并且使用有效的套接字列表,我们可以继续进行异步发送。

    但是,此时您可以根据需要使用此列表 - cliente.connections[0].out_buffer += 'I am data' 会完成这项工作,但您可能希望更好地控制它。如果是,请继续。

    '为谁,由我'

    为了异步发送数据,我们需要将 asyncore 从控制线程中分离出来,我们将在其中输入要发送的内容和发送给谁。

    class ServerThread(threading.Thread):
        def __init__(self):
            threading.Thread.__init__(self)
            self.daemon = True # if thread is a daemon, it'll be killed when main program exits
            self.cliente = Server()
            self.start()
    
        def run(self):
            print 'Starting server thread...'
            asyncore.loop()
    
    thread = ServerThread()
    
    while True:
        msg = raw_input('Enter IP and message divided by semicolon: ')
    
        if msg == 'exit':
            break
    
        ip, data = msg.split('; ')
        for sock in thread.cliente.connections:
            if sock.addr[0] == ip:
                sock.out_buffer += data
                break
    

    这将起作用并等待目标 IP 和数据。记得连接客户端。

    正如我所说,您可以使用任何东西来指示哪个套接字是哪个。它可以是一个带有字段的类,例如。 IP 和用户名,因此您只能向用户名以“D”开头的对等方发送数据。

    但是……

    这个解决方案有点粗糙,如果你想很好地发送数据,需要更好地了解异步模块(这里它有一些延迟,因为select() 的工作原理)并充分利用这个socket 包装器。 Herehere 是一些资源。

    语法注释

    虽然您的代码现在可以工作,但您的代码有一些不好的地方。指令末尾的分号不会导致错误,但几乎每个类属性的变量都会导致错误。例如这里:

    def handle_accept(self):
        self.sock,self.addr = self.accept();
        if self.addr:
            print self.addr[0];
        handler = EchoHandler(self.sock);
    

    self.sockself.addr 可能在该类中用于其他用途(例如与套接字相关的事物;地址),并且覆盖它们可能会造成麻烦。用于请求的方法不应保存先前操作的状态。

    我希望 Python 足够好,让你继续使用它!

    编辑: sock.addr[0] 可以用来代替sock.socket.getpeername()[0] 但它要求self.addr 不能被修改,所以handle_accept() 应该是这样的:

    def handle_accept(self):
        sock, addr = self.accept()
        if addr:
            print addr[0]
        handler = EchoHandler(sock, self)
        self.connections.append(handler)
    

    【讨论】:

      猜你喜欢
      • 2015-11-22
      • 1970-01-01
      • 2010-12-29
      • 2020-11-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-22
      • 1970-01-01
      相关资源
      最近更新 更多