2014-02-16 5 views
0

Я работаю над клиентом для этого чат-сервера, но у меня есть проблема. Сервер использует асинхронный модуль 3.4RC1 Python.asyncio проект. Что мне не хватает?

Поведение:

Мой клиент подключается. Мой второй клиент подключается. Либо может отправлять сообщения на сервер. НО, сервер не передает их так, как должен, в обычном общедоступном чате.

User1: Hello. Прессы Введите.

User2 не видит.

User2: Кто-нибудь есть? Прессы Введите.

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

Вот не резьбовой код сервера я написал. отлично работает, но ТОЛЬКО между двумя людьми. Как можно обновить этот код для трансляции каждого сообщения, полученного для всех подключенных клиентов?

# 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() 
+0

Я получаю сообщение об ошибке: 'AttributeError: объект '_WindowsSelectorEventLoop' не имеет атрибута«sock_send'', а также 'buf' в '_peer_loop' не определен. – poke

+0

Ops! У меня было 3 строки кода, прокомментированных в коде сервера. Копировать, Вставить, Попробуй еще раз. – ASPiRE

+0

«AttributeError» по-прежнему сохраняется для меня. – poke

ответ

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

ahh ... threads. У меня нет опыта с потоками. Но ... Я могу опубликовать еще один код сервера. Возможно, вы могли бы предоставить «пример потока» на его основе? Обновление исходного сообщения. Подожди. – ASPiRE

+0

@Vini Ну, вы можете просто использовать 'concurrent.futures'. Простой пример для [ThreadPoolExecutor] (http://docs.python.org/3/library/concurrent.futures.html#threadpoolexecutor). В вашем случае у вас будет одна функция, которая будет иметь бесконечное чтение цикла из сокета, а другая функция с бесконечным циклом, ожидающим ввода и отправки этого пользователя. – poke

+0

Я ... не могу представить себе вещи таким ясным образом. Но я буду читать. Не стесняйтесь бить e. – ASPiRE

Смежные вопросы