Более менее дышащий код.
Код Клиента:
Код | #Сети ЭВМ. лр №3 #мультиклиентский чат. клиентская часть. Автор: deHimer
import socket from threading import Thread
#глобалные переменные клиента host = 'localhost' tcp_socket_port = 13
opp_udp_host_port = () # host, port оппонента в режиме приватноо чата
#режим чата. 1 - общий. 2 - индивидуальный chat_mode = 1
# UDP сервер принимающий входящие сообщения и ответственный за получение # приглашений от другого пользователя чата на личную переписку
class UDP_server(Thread): def __init__(self, udp_sock): self.udp_server_socket = udp_sock Thread.__init__(self) def run(self): global opp_udp_host_port global chat_mode # бесконечный цикл ожидающий новых сообщений while True: #получаем сообщение/команду data, address = self.udp_server_socket.recvfrom(100) if data != '!privateChat': #вывод сообщения из общего чата print data else: #обработка запроса на установление приватного чата #узнаем как зовут оппонента data, address = self.udp_server_socket.recvfrom(100) print data #отвечаем, хочется ли data = raw_input('now enter \'yes\' or \'no\' ') self.udp_server_socket.sendto(data, address) # если мы согласны, то мы должны перейти в режим личного чата # и получить адрес UDP порта оппонента if data == 'yes': #получить имя хоста и номер порта оппонента opp_host, address = self.udp_server_socket.recvfrom(25) self.udp_server_socket.sendto('udp host accept', address) opp_port, address = self.udp_server_socket.recvfrom(5) self.udp_server_socket.sendto('udp port accept', address) opp_udp_host_port = (opp_host, int(opp_port)) chat_mode = 2 else: pass
#настрока сокета и запуск UDP сервера udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) udp_socket.bind((host, 0)) # если указан 0 - выберется совбодный порт
#узнаем, какой порт получил наш UDP сервер udp_socket_host_port = udp_socket.getsockname() udp_socket_port = str(udp_socket_host_port[1])
print 'you on port'+udp_socket_port
#запуск сервера UDP UDP_server(udp_socket).start()
#настрока TCP клиента, выполняющего связь с сервером
# создание TCP клиента tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) tcp_socket.connect((host, tcp_socket_port))
#отправка серверу адреса UDP сервера tcp_socket.send(host) tcp_socket.recv(100)
tcp_socket.send(udp_socket_port) tcp_socket.recv(100)
#выбор клиентом имени и согласование его с сервером while True: user_name = raw_input('Select the desired name: ') tcp_socket.send(user_name) server_answer = tcp_socket.recv(100) if server_answer=='Name valid': print 'Name valid. Connection is established.' break else: print server_answer #создание UDP сокета для приватного общения с сервером оппонента udp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) print "!help !common_chat !clients_list !private_chat !exit\n"
#основной цикл общения с TCP сервером while True: user_input = raw_input('') if user_input == '!clients_list': #получение списка контактов tcp_socket.send(user_input) print tcp_socket.recv(64500) elif user_input=='!common_chat': if chat_mode == 2: udp_client_socket.sendto(user_name + 'out from private chat', opp_udp_host_port) #переход в режим общего чата chat_mode = 1 tcp_socket.send(user_input) print 'you in common chat mode' elif user_input=='!help': print "!help !common_chat !clients_list !private_chat !exit\n" elif user_input=='!exit': tcp_socket.send('!exit') break elif user_input=='!private_chat': #запрос на создание приватного чата tcp_socket.send(user_input) #отправка имени оппонента opp_name = raw_input('Enter opponent name: ') tcp_socket.send(opp_name) #получение результата запроса answer = tcp_socket.recv(100) if answer=='yes': #получаем адресс UDP сервера оппонента opponent_host = tcp_socket.recv(100) tcp_socket.send('opponent udp host accept') opponent_port = tcp_socket.recv(100) opponent_port = int(opponent_port) tcp_socket.send('opponent udp port accept') opp_udp_host_port = (opponent_host, opponent_port) chat_mode = 2 print 'you in private chat mode' else: print answer else: #получение и отправка сообщений if chat_mode==1: tcp_socket.send(user_name+' com> '+user_input) else: #тут должна быть отправка данных на UDP сервер оппонента udp_client_socket.sendto(user_name+' priv> '+user_input, opp_udp_host_port)
tcp_socket.close()
|
Код Сервера:
Код | #Сети ЭВМ. лр №3 #мультиклиентский чат. серверная часть. Автор: deHimer
import socket from threading import Thread import re
#глобальные переменные host = 'localhost' tcp_serv_port = 13
clients = {} #[name] -> (chat_mode, (udp_host, udp_port))
#поток обрабатывающий команды/сообщения пользователя class Connect(Thread): def __init__(self, client_socket, client_host_port): self.client_tcp_socket = client_socket self.client_tcp_addres = client_host_port Thread.__init__(self) def run(self): #создание UDP клиента self.udp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) #получение адреса UDP сервера клиента self.client_udp_host = self.client_tcp_socket.recv(100) self.client_tcp_socket.send('udp host received') self.client_udp_port = int(self.client_tcp_socket.recv(100)) self.client_tcp_socket.send('udp port received') #получение имени клиента have_connection = True try: self.user_name = self.client_tcp_socket.recv(20) except: have_connection = False while have_connection: #проверка имени на уникальность и правильность if clients and (self.user_name in clients.keys()): self.client_tcp_socket.send('Name chosen busy. Choose another name') else: if re.search('\W', self.user_name): self.client_tcp_socket.send("Name invalid") else: self.client_tcp_socket.send("Name valid") #сохраняем данные пользователя clients[self.user_name]=(1, (self.client_udp_host, self.client_udp_port)) print ('User %s has connected' % self.user_name) break self.user_name = self.client_tcp_socket.recv(20) #цикл связи с клиентом have_connection = True while have_connection: try: buffer = self.client_tcp_socket.recv(1024) except: have_connection = False break if buffer == '!clients_list': #составление списка клиентов connected_clients_list='' for client in clients.keys(): connected_clients_list += client + ' ' self.client_tcp_socket.send(connected_clients_list) elif buffer == '!common_chat': #переключение в общий чат client = clients[self.user_name] client = (1, client[1]) clients[self.user_name] = client elif buffer =='!exit': have_connection = False print ('User %s is disconnected' % self.user_name) del clients[self.user_name] break elif buffer == '!private_chat': #создание приватного чата #получение имени оппонента try: opponent_name = self.client_tcp_socket.recv(100) except: have_connection = False break #проверка на существование выбранного оппонента if opponent_name in clients.keys(): #запрос согласия оппонента на установление контакта opp_mode_host_port = clients[opponent_name] self.udp_client_socket.sendto('!privateChat', opp_mode_host_port[1]) self.udp_client_socket.sendto('Allow chat with ' + self.user_name + '. (before answering, press Enter)', opp_mode_host_port[1])
opp_answer = self.udp_client_socket.recv(100)
if opp_answer == 'yes': #отправка оппоненту адреса UDP сервера клиента print opp_mode_host_port[1] self.udp_client_socket.sendto(str(self.client_udp_host), 0, opp_mode_host_port[1]) data, address = self.udp_client_socket.recvfrom(15) print data self.udp_client_socket.sendto(str(self.client_udp_port), 0, opp_mode_host_port[1]) data, address = self.udp_client_socket.recvfrom(15) print data #изменение состояний клиента и оппонента #переключение оппонента в режим прив. чата opp_date = clients[opponent_name] new_opp_mode = (2, opp_date[1]) clients[opponent_name] = new_opp_mode #переключение пользователя client = clients[self.user_name] client = (2, client[1]) clients[self.user_name] = client #пишем клиенту что все гуд self.client_tcp_socket.send('yes') #отправляем клиенту адрес UDP сервера оппонента opp_host_port = opp_date[1] self.client_tcp_socket.send(str(opp_host_port[0])) self.client_tcp_socket.recv(100) self.client_tcp_socket.send(str(opp_host_port[1])) self.client_tcp_socket.recv(100) else: #иначе пишем что с ним не хотят иметь дел self.client_tcp_socket.send('no') else: #если такого нет self.client_tcp_socket.send('Opponent with the same name is missing.') else: client_mode_address = clients[self.user_name] client_chat_mode = client_mode_address[0] if client_chat_mode == 1: for client in clients.values(): if (client[0] == 1) and (client[1] != (self.client_udp_host, self.client_udp_port)): self.udp_client_socket.sendto(buffer, client[1]) else: self.udp_client_socket.sendto(buffer, companion[1]) self.udp_client_socket.close() self.client_tcp_socket.close() tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) tcp_server_socket.bind((host, tcp_serv_port)) tcp_server_socket.listen(5)
#ожидание и подключние новых клиентов while True: client_socket, client_host_port = tcp_server_socket.accept() Connect(client_socket, client_host_port).start()
|
Добавлено через 3 минуты и 39 секунд С самого начала хотел на Tkinter'e сделать интерфейс, но на то что выше ушло времени больше чем ожидалось. Если есть желающие привинтить интерфейс и улучшить код - только за. Буду приятно удивлен увидеть тут развитие темы |