2016-03-17 4 views
3

Я пытаюсь создать простое приложение чата с помощью сокетов (python). Если клиент может отправить сообщение серверу и серверу, просто передайте сообщение всем другим клиентам, кроме тех, кто его отправил.Создание простого приложения чата в Python (Sockets)

Клиент имеет две нити, которые бегут навсегда

send: Отправить просто отправляет сообщение cleints к серверу.

receive: Получить сообщение с сервера.

Сервер также имеет две темы, которые бегут навсегда

accept_cleint: Для того, чтобы принять входящее соединение от клиента.

broadcast_usr: Принимает сообщение от клиента и передает его всем другим клиентам.

Но я получаю ошибочный результат (см. Изображение ниже). Все потоки предполагают быть активными все время, но иногда клиент может отправлять сообщения, иногда это невозможно. Скажем, например, Трейси отправляет «привет» 4 раза, но его не транслируют, когда Джон говорит «до свидания» 2 раза, а затем 1 раз его сообщение получает ловушку. Кажется, есть проблема thread synchronization на сервере, я не уверен. Пожалуйста, скажите мне, что случилось.

enter image description here

Ниже приведен код.

chat_client.py

import socket, threading 

def send(): 
    while True: 
     msg = raw_input('\nMe > ') 
     cli_sock.send(msg) 

def receive(): 
    while True: 
     sen_name = cli_sock.recv(1024) 
     data = cli_sock.recv(1024) 

     print('\n' + str(sen_name) + ' > ' + str(data)) 

if __name__ == "__main__": 
    # socket 
    cli_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 

    # connect 
    HOST = 'localhost' 
    PORT = 5023 
    cli_sock.connect((HOST, PORT))  
    print('Connected to remote host...') 
    uname = raw_input('Enter your name to enter the chat > ') 
    cli_sock.send(uname) 

    thread_send = threading.Thread(target = send) 
    thread_send.start() 

    thread_receive = threading.Thread(target = receive) 
    thread_receive.start() 

chat_server.py

import socket, threading 

def accept_client(): 
    while True: 
     #accept  
     cli_sock, cli_add = ser_sock.accept() 
     uname = cli_sock.recv(1024) 
     CONNECTION_LIST.append((uname, cli_sock)) 
     print('%s is now connected' %uname) 

def broadcast_usr(): 
    while True: 
     for i in range(len(CONNECTION_LIST)): 
      try: 
       data = CONNECTION_LIST[i][1].recv(1024) 
       if data: 
        b_usr(CONNECTION_LIST[i][1], CONNECTION_LIST[i][0], data) 
      except Exception as x: 
       print(x.message) 
       break 

def b_usr(cs_sock, sen_name, msg): 
    for i in range(len(CONNECTION_LIST)): 
     if (CONNECTION_LIST[i][1] != cs_sock): 
      CONNECTION_LIST[i][1].send(sen_name) 
      CONNECTION_LIST[i][1].send(msg) 

if __name__ == "__main__":  
    CONNECTION_LIST = [] 

    # socket 
    ser_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 

    # bind 
    HOST = 'localhost' 
    PORT = 5023 
    ser_sock.bind((HOST, PORT)) 

    # listen  
    ser_sock.listen(1) 
    print('Chat server started on port : ' + str(PORT)) 

    thread_ac = threading.Thread(target = accept_client) 
    thread_ac.start() 

    thread_bs = threading.Thread(target = broadcast_usr) 
    thread_bs.start() 
+2

Я думаю, что проблема связана с циклами ваших клиентских потоков, хотя ваш сервер также должен иметь возможность обращаться с клиентским отключением. – pholtz

+0

Just FYI, ** Twisted ** - это библиотека Python для создания поточных серверов. – Fattie

ответ

1

Ok я солгал мой комментарий выше, извините. На самом деле проблема заключается в функции broadcast_usr() на сервере. Он блокирует метод recv() и запрещает всем, кроме текущего пользователя, разговаривать за один раз, когда он проходит через цикл for. Чтобы исправить это, я изменил программу server.py, чтобы создать новый поток broadcast_usr для каждого клиентского соединения, которое он принимает. Надеюсь, это поможет.

import socket, threading 

def accept_client(): 
    while True: 
     #accept  
     cli_sock, cli_add = ser_sock.accept() 
     uname = cli_sock.recv(1024) 
     CONNECTION_LIST.append((uname, cli_sock)) 
     print('%s is now connected' %uname) 
     thread_client = threading.Thread(target = broadcast_usr, args=[uname, cli_sock]) 
     thread_client.start() 

def broadcast_usr(uname, cli_sock): 
    while True: 
     try: 
      data = cli_sock.recv(1024) 
      if data: 
       print "{0} spoke".format(uname) 
       b_usr(cli_sock, uname, data) 
     except Exception as x: 
      print(x.message) 
      break 

def b_usr(cs_sock, sen_name, msg): 
    for client in CONNECTION_LIST: 
     if client[1] != cs_sock: 
      client[1].send(sen_name) 
      client[1].send(msg) 

if __name__ == "__main__":  
    CONNECTION_LIST = [] 

    # socket 
    ser_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 

    # bind 
    HOST = 'localhost' 
    PORT = 5023 
    ser_sock.bind((HOST, PORT)) 

    # listen  
    ser_sock.listen(1) 
    print('Chat server started on port : ' + str(PORT)) 

    thread_ac = threading.Thread(target = accept_client) 
    thread_ac.start() 

    #thread_bs = threading.Thread(target = broadcast_usr) 
    #thread_bs.start() 
+0

Ваш код работает нормально, но есть небольшая ошибка. Отправитель должен отправить 2 сообщения для трансляции. Кажется, что 'sen_name = cli_sock.recv (1024)' и 'data = cli_sock.recv (1024)' на стороне клиента получают имя отправителя и сообщение. Пожалуйста, обратитесь к приведенному ниже снимку экрана. http://postimg.org/image/3mnwmuyvj/ – Atinesh

1

Я попытался обойти ошибку, которую вы сказали @ Атинеш. Клиенту будет задано имя пользователя один раз, и это «uname» будет включено в данные для отправки. Посмотрите, что я сделал с 'отправить' функция.

Для облегчения визуализации я добавил '\ t' ко всем полученным сообщениям.

import socket, threading 

def send(uname): 
    while True: 
     msg = raw_input('\nMe > ') 
     data = uname + '>' + msg 
     cli_sock.send(data) 

def receive(): 
    while True: 
     data = cli_sock.recv(1024) 
     print('\t'+ str(data)) 

if __name__ == "__main__": 
    # socket 
    cli_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 

    # connect 
    HOST = 'localhost' 
    PORT = 5023 

    uname = raw_input('Enter your name to enter the chat > ') 

    cli_sock.connect((HOST, PORT))  
    print('Connected to remote host...') 


    thread_send = threading.Thread(target = send,args=[uname]) 
    thread_send.start() 

    thread_receive = threading.Thread(target = receive) 
    thread_receive.start() 

Вы также должны соответствующим образом изменить код сервера.

сервер.ру

import socket, threading 

def accept_client(): 
    while True: 
     #accept  
     cli_sock, cli_add = ser_sock.accept() 
     CONNECTION_LIST.append(cli_sock) 
     thread_client = threading.Thread(target = broadcast_usr, args=[cli_sock]) 
     thread_client.start() 

def broadcast_usr(cli_sock): 
    while True: 
     try: 
      data = cli_sock.recv(1024) 
      if data: 
       b_usr(cli_sock, data) 
     except Exception as x: 
      print(x.message) 
      break 

def b_usr(cs_sock, msg): 
    for client in CONNECTION_LIST: 
     if client != cs_sock: 
      client.send(msg) 

if __name__ == "__main__":  
    CONNECTION_LIST = [] 

    # socket 
    ser_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 

    # bind 
    HOST = 'localhost' 
    PORT = 5023 
    ser_sock.bind((HOST, PORT)) 

    # listen  
    ser_sock.listen(1) 
    print('Chat server started on port : ' + str(PORT)) 

    thread_ac = threading.Thread(target = accept_client) 
    thread_ac.start() 

Вещи, которые изменили на стороне сервера являются: пользователь, который подключен и пользователь, который говорил не видел больше. Я не знаю, значило бы это, если ваша цель - подключить клиентов. Возможно, если вы хотите строго контролировать клиентов через сервер, может быть другой способ.

+1

В строке сервера в строке 17 есть ошибка с отступом. Нужно просто перемещать 1 символ слева. – Adam893

+0

oops. не заметил этого. Спасибо, что указали это. :) – ajdr

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