asyncio项目。我错过了什么?

时间:2014-02-16 20:59:23

标签: sockets python-3.x asyncsocket python-asyncio

我一直在为这个聊天服务器的客户端工作,但我遇到了一些挑战。服务器使用Python的3.4RC1 asyncio模块。

行为:

我的客户连接。我的第二个客户连接。要么可以向服务器发送消息,要么服务器不在正常的公共聊天室中广播它们。

User1:您好。 按下回车。

User2没有看到它。

用户2:有人吗? 按下回车。

User2看到User1:Hello。和User2:那里的任何人?

只是......奇怪。不确定我错过了什么。

以下是文件。试一试。

服务器:

from socket import socket, SO_REUSEADDR, SOL_SOCKET
from asyncio import Task, coroutine, get_event_loop

class Peer(object):
    def __init__(self, server, sock, name):
        self.loop = server.loop
        self.name = name
        self._sock = sock
        self._server = server
        Task(self._peer_handler())

    def send(self, data):
        return self.loop.sock_send(self._sock, data.encode('utf-8'))

    @coroutine
    def _peer_handler(self):
        try:
            yield from self._peer_loop()
        except IOError:
            pass
        finally:
            self._server.remove(self)

    @coroutine
    def _peer_loop(self):
        while True:
            buf = yield from self.loop.sock_recv(self._sock, 1024)
            if buf == b'':
                break
            self._server.broadcast('%s: %s' % (self.name, buf.decode('utf-8')))

class Server(object):
    def __init__(self, loop, port):
        self.loop = loop
        self._serv_sock = socket()
        self._serv_sock.setblocking(0)
        self._serv_sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
        self._serv_sock.bind(('',port))
        self._serv_sock.listen(5)
        self._peers = []
        Task(self._server())

    def remove(self, peer):
        self._peers.remove(peer)
        self.broadcast('Peer %s quit!' % (peer.name,))

    def broadcast(self, message):
        for peer in self._peers:
            peer.send(message)

    @coroutine
    def _server(self):
        while True:
            peer_sock, peer_name = yield from self.loop.sock_accept(self._serv_sock)
            peer_sock.setblocking(0)
            peer = Peer(self, peer_sock, peer_name)
            self._peers.append(peer)
            self.broadcast('Peer %s connected!' % (peer.name,))

def main():
    loop = get_event_loop()
    Server(loop, 1234)
    loop.run_forever()

if __name__ == '__main__':
    main()

客户端:

# import socket
from socket import *
# form socket import socket, bind, listen, recv, send

HOST = 'localhost' #localhost / 192.168.1.1
# LAN - 192.168.1.1
PORT = 1234
s = socket(AF_INET, SOCK_STREAM)# 98% of all socket programming will use AF_INET and SOCK_STREAM
s.connect((HOST, PORT))

while True:
    message = input("Your Message: ")
    encoded_msg = message.encode('utf-8')
    s.send(encoded_msg)
    print('Awaiting Reply..')
    reply = s.recv(1024)
    decoded_reply = reply.decode('utf-8')
    decoded_reply = repr(decoded_reply)
    print('Received ', decoded_reply)

s.close()

这是我写的非线程服务器代码。工作得很好,但只有2人之间。如何更新此代码以将收到的每条消息广播到所有连接的客户端?

# import socket
from socket import *
# form socket import socket, bind, listen, recv, send

HOST = 'localhost' #localhost / 192.168.1.1
# LAN - 192.168.1.1
PORT = 1234
s = socket(AF_INET, SOCK_STREAM) # 98% of all socket programming will use AF_INET and SOCK_STREAM
s.bind((HOST, PORT))
s.listen(5) # how many connections it can receive at one time
conn, addr = s.accept() # accept the connection
print('Connected by', addr) # print the address of the person connected

while True:
    data = conn.recv(1024)
    decoded_data = data.decode('utf-8')
    data = repr(decoded_data)
    print('Received ', decoded_data)
    reply = input("Reply: ")
    encoded_reply = reply.encode('utf-8')
    conn.sendall(encoded_reply)
    print('Server Started')
conn.close()

1 个答案:

答案 0 :(得分:0)

好的,让我们考虑一下您的客户做了什么。您要求发送消息,阻止用户输入。然后发送该消息并接收服务器上的任何内容。然后,再次阻止,等待另一条消息。

因此,当客户端A发送文本时,客户端B可能会阻止用户输入。因此,B实际上不会检查服务器是否发送了任何内容。只有发送了一些内容后,它才会显示的内容。

显然,在聊天中,您不希望阻止用户输入。即使用户没有发送消息,您也希望继续从服务器接收新消息。所以你需要将它们分开,并以异步方式运行。

我还没有对asyncio做过多少工作,所以我真的不知道这是否可以很好地完成它,但你基本上只需要将读取和发送分成两个独立的并发任务,例如使用线程或concurrent.futures


使用threading

快速举例说明您可以做些什么
from socket import *
from threading import Thread

HOST = 'localhost'
PORT = 1234
s = socket(AF_INET, SOCK_STREAM)
s.connect((HOST, PORT))

def keepReading ():
    try:
        while True:
            reply = s.recv(1024).decode()
            print('Received ', reply)
    except ConnectionAbortedError:
        pass

t = Thread(target=keepReading)
t.start()

try:
    while True:
        message = input('')
        s.send(message.encode())
except EOFError:
    pass
finally:
    s.close()