簡體   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