Здравия Всем! Выставляю на обсуждение вопрос, над которым бьюсь несколько дней. Есть сервер и множество клиентов. Вся работа выполняется на сокетах. Как сделать так чтобы пользователь мог в одно и то же время и получать сообщения из общего чата и писать их? Я думал просто пока пользователь не начнет ввод - ждать сообщений и выводить их. Мои варианты: 2 потока, один принимает данные и выводит их на экран. или 1 цикл с проверкой на пользовательский ввод с клавиатуры. Если ввода не происходит - слушать сокет. Если первый вариант - то надо на сервер отправить информацию о номере порта UDP сервера, ожидающего сообщения. Во втором мне не понятно как сделать ожидание события "нажатие клавиши". Какие идеи? Код с попыткой реализации первого варианта: Сервер: Код | import socket import threading import re
host = 'localhost' common_chat_port = 14 individual_port = 13
#имя клиента -> (статус, (хост, порт)). #статус - в общем чате(1)/личная переписка(2) clients = {}
class Common_messages_send(threading.Thread): """ Рассылка сообщений клиентам из состоящим в общем чате. """ def __init__(self, sock, data, sendler_addres): threading.Thread.__init__(self) self.sock = sock self.data = data self.sendler_addres = sendler_addres def run(self): for client in clients.values(): #отправка только если статус в общем чате и получатель не является оптправителем if (client[0] == 1) and (client[1]!=self.sendler_addres):
self.sock.sendto(self.data, client[1]) print ' cm_done'
class Common_chat(threading.Thread): """ Процесс, получающий и перенаправляющий клиентам сообщения для общего чата. """ def __init__(self, sock): threading.Thread.__init__(self) self.sock = sock def run(self):
while True:
data, sendler_addres = self.sock.recvfrom(1024) Common_messages_send(self.sock, data, sendler_addres).start() print ' cc_done' class Clients(threading.Thread): """ Процесс, поддерживающий связь с конкретным пользователем. Выполняет команды от пользователя и организует личную переписку. """ def __init__(self, sock, host_port): threading.Thread.__init__(self) self.sock = sock self.host_port = host_port def run(self): have_connection = True #получение, проверка и сохранение информации о клиенте try: user_name = self.sock.recv(20) except: have_connection = False while have_connection: if clients and (user_name in clients.keys()): self.sock.send('Name chosen busy. Choose another name') else: if re.search('\W', user_name): self.sock.send("Login invalid") else: self.sock.send("Ok") #сохраняем данные пользователя clients[user_name]=(1, self.host_port) # 1 - print ('User %s has connected' % user_name) break user_name = self.sock.recv(20) #информация о собеседнике (в режиме работы 2 - индивидуальный чат) #[name]->(host, port) companion = {} #цикл работы с клиентом have_connection = True while have_connection: try: buffer = self.sock.recv(1024) except: have_connection = False break if buffer == '!c': connected_clients_list='' for client in clients.keys(): connected_clients_list += client + ' ' self.sock.send(connected_clients_list) elif buffer == '!a': client = clients[user_name] client[0] = 1 clients[user_name] = client elif buffer =='!e': have_connection = False print ('User %s is disconnected' % user_name) self.sock.close()
#создание и настрока сокета для общего чата common_chat_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) common_chat_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) common_chat_socket.bind((host, common_chat_port))
#создание и настрока сокета для соединения с клиентом individual_chat_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) individual_chat_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) individual_chat_socket.bind((host, individual_port)) individual_chat_socket.listen(5)
#запуск потока реализующего общий чат Common_chat(common_chat_socket).start()
while True:
#создание потока связи с клиентом sock, client_host_port = individual_chat_socket.accept() Clients(sock, client_host_port).start()
|
Клиент: Код | import socket import threading
#параметры соединений host = 'localhost' common_chat_port = 14 individual_port = 13
common_chat_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client_socket.connect((host, individual_port))
#режим чата. 1 - общий. 2 - индивидуальный chat_mode = 1
class Common_chat_client(threading.Thread): def __init__(self, sock): self.sock = sock threading.Thread.__init__(self) def run(self): global chat_mode self.sock.sendto('new user connected', ('localhost', 14)) while True: if chat_mode==1: buffer, addres=self.sock.recvfrom(1024) print 'All>'+ buffer
class Work(threading.Thread): def __init__(self, client_sock, common_sock): self.client_sock = client_sock self.common_sock = common_sock threading.Thread.__init__(self) def run(self): global chat_mode #выбор имени для клиента while True: user_name = raw_input('Select the desired name: ') self.client_sock.send(user_name) server_answer = self.client_sock.recv(100) if server_answer=='Ok': print 'Name valid. Connection is established.' break else: print server_answer
print "!h - help\n!a - common chat\n!c - client list\n!l - chat with login\n!e - exit"
#основной цикл работы while True: buffer = raw_input('>') if buffer=='!c': #получение списка контактов command = '!c' self.client_sock.send(command) connected_clients_list = self.client_sock.recv(64000) print connected_clients_list elif buffer=='!a': chat_mode = 1 self.client_socket.send(buffer) elif buffer=='!h': print "!h - help\n!a - common chat\n!c - client list\n!l - chat with login\n!e - exit" elif buffer=='!e': self.client_socket.send('!e') break elif buffer=='!l': chat_mode = 2 pass else: #получение и отправка сообщений if chat_mode==1: self.common_sock.sendto(buffer, (host, common_chat_port)) else: pass
client_socket.close() Work(client_socket ,common_chat_socket).start() Common_chat_client(common_chat_socket).start()
|
|