简体   繁体   English

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

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

I have to send data only to a connection, as I can do? 我可以将数据仅发送到连接吗?

server: 服务器:

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

this line is an example fails, but I want to send data to zero sock: 这行是一个示例失败,但我想将数据发送到零袜子:

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

for example, if I have 5 sockets choose who to send the data 例如,如果我有5个套接字,请选择谁发送数据

Explanation 说明

You tried to get sock from list and execute its send method. 您试图从列表中获取袜子并执行其send方法。 This causes error, because EchoHandler neither has sock attribute nor it's a list of sockets. 这会导致错误,因为EchoHandler既没有sock属性,也不是套接字列表。 The right method is to get instance of EchoHandler you want (based on, eg. IP address, or slots assigned by some user-defined protocol) and then use its send method - here (with dispatcher_with_send ) its also better to use special buffer for that than send. 正确的方法是获取所需的EchoHandler实例(基于IP地址或某些用户定义的协议分配的插槽),然后使用其send方法-在此(与dispatcher_with_send一起使用)最好使用特殊的缓冲区那比发送。

EchoHandler instantion is created on every accept of connection - from then it is an established channel for communication with the given host. EchoHandler实例是在每次接受连接时创建的-从那时起,它是与给定主机进行通信的已建立通道 Server listens for any non-established connection, while EchoHandler s use socks (given by Server in handle_accept ) for established ones, so there are as many EchoHandler instances as connections. Server侦听任何未建立的连接,而EchoHandler使用袜子(由Serverhandle_accept )来建立袜子,因此EchoHandler实例与连接一样多。

Solution

You need to make some list of connections ( EchoHandler instantions; we'll use buffer, not socket's send() directly) and give them opportunity to delete their entries on close: 您需要列出一些连接列表( 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 is now aware of server instance and can remove its socket from list. EchoHandler现在知道服务器实例,可以从列表中删除其套接字。 This echo example is now fully functional, and with working socket list we can proceed to asynchronous sending. 现在,此回显示例已完全可用,并且在工作套接字列表的情况下,我们可以继续进行异步发送。

But, at this point you can use this list as you wanted - cliente.connections[0].out_buffer += 'I am data' will do the work, but probably you'd want some better controlling of this. 但是,此时,您可以根据需要使用此列表cliente.connections[0].out_buffer += 'I am data'可以完成工作,但是可能您希望对此有更好的控制。 If yes, go ahead. 如果是,请继续。

'For whom, by me' '为谁,由我'

In order to send data asynchronously, we need to separate asyncore from our control thread, in which we'll enter what to send and to whom. 为了异步发送数据,我们需要将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

This will work and wait for destination IP and data. 这将起作用并等待目标IP和数据。 Remember to have client connected. 记住要连接客户端。

As I said, you can use anything to indicate which socket is which. 正如我所说,您可以使用任何东西来指示哪个套接字。 It can be a class with fields for eg. 它可以是带有例如字段的类。 IP and username, so you could send data only to peers whose usernames start with 'D'. IP和用户名,因此您只能将数据发送给用户名以“ D”开头的对等方。

But... 但...

This solution is a bit rough and needs better knowledge of asyncore module if you want to send data nicely (here it has some delay due to how select() works) and make good use of this socket wrapper. 如果您想很好地发送数据(此处由于select()工作方式会有所延迟),并且要充分利用此socket包装器,则此解决方案有点粗糙,并且需要对asyncore模块有更好的了解。 Here and here are some resources. 这里这里有一些资源。

Syntax note 语法说明

Although your code will now work, your code has some not-nice things. 尽管您的代码现在可以使用,但是您的代码有一些不错的东西。 Semicolons on instructions ends don't cause errors, but making nearly every variable of class attribute can lead to them. 指令末尾的分号不会导致错误,但是使class属性的几乎每个变量都可能导致错误。 For example here: 例如这里:

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

self.sock and self.addr might be used in that class for something other (eg. socket-related thing; addresses) and overriding them could make trouble. self.sockself.addr可能在该类中用于其他用途(例如与套接字相关的事物;地址),而覆盖它们可能会造成麻烦。 Methods used for requests should never save state of previous actions. 用于请求的方法应永远不要保存先前操作的状态。

I hope Python will be good enough for you to stay with it! 我希望Python足以让您坚持使用它!

Edit: sock.addr[0] can be used instead of sock.socket.getpeername()[0] but it requires self.addr not to be modified, so handle_accept() should look like this: 编辑:可以使用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