繁体   English   中英

python asyncore服务器仅将数据发送到一只袜子

[英]python asyncore server send data to only one sock

我可以将数据仅发送到连接吗?

服务器:

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个套接字,请选择谁发送数据

说明

您试图从列表中获取袜子并执行其send方法。 这会导致错误,因为EchoHandler既没有sock属性,也不是套接字列表。 正确的方法是获取所需的EchoHandler实例(基于IP地址或某些用户定义的协议分配的插槽),然后使用其send方法-在此(与dispatcher_with_send一起使用)最好使用特殊的缓冲区那比发送。

EchoHandler实例是在每次接受连接时创建的-从那时起,它是与给定主机进行通信的已建立通道 Server侦听任何未建立的连接,而EchoHandler使用袜子(由Serverhandle_accept )来建立袜子,因此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包装器,则此解决方案有点粗糙,并且需要对asyncore模块有更好的了解。 这里这里有一些资源。

语法说明

尽管您的代码现在可以使用,但是您的代码有一些不错的东西。 指令末尾的分号不会导致错误,但是使class属性的几乎每个变量都可能导致错误。 例如这里:

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)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM