def run(self): logger.debug('Запущен процесс - приёмник собщений с сервера.') while self.running: # Отдыхаем секунду и снова пробуем захватить сокет. # если не сделать тут задержку, то отправка может достаточно долго # ждать освобождения сокета. time.sleep(1) with socket_lock: try: self.transport.settimeout(0.5) message = get_my_message(self.transport) except OSError as err: if err.errno: logger.critical(f'Потеряно соединение с сервером.') self.running = False self.connection_lost.emit() # Проблемы с соединением except (ConnectionError, ConnectionAbortedError, ConnectionResetError, json.JSONDecodeError, TypeError): logger.debug(f'Потеряно соединение с сервером.') self.running = False self.connection_lost.emit() # Если сообщение получено, то вызываем функцию обработчик: else: logger.debug(f'Принято сообщение с сервера: {message}') self.process_server_ans(message) finally: self.transport.settimeout(5)
def user_list_request(sock, username): LOGGER.debug(f'Запрос списка известных пользователей {username}') req = {ACTION: USERS_REQUEST, TIME: time.time(), ACCOUNT_NAME: username} send_message(sock, req) ans = get_my_message(sock) if RESPONSE in ans and ans[RESPONSE] == 202: return ans[LIST_INFO] else: raise ServerError
def contacts_list_request(sock, name): LOGGER.debug(f'Запрос контакт листа для пользователся {name}') req = {ACTION: GET_CONTACTS, TIME: time.time(), USER: name} LOGGER.debug(f'Сформирован запрос {req}') send_message(sock, req) ans = get_my_message(sock) LOGGER.debug(f'Получен ответ {ans}') if RESPONSE in ans and ans[RESPONSE] == 202: return ans[LIST_INFO] else: raise ServerError
def remove_contact(self, contact): logger.debug(f'Удаление контакта {contact}') req = { ACTION: REMOVE_CONTACT, TIME: time.time(), USER: self.username, ACCOUNT_NAME: contact } with socket_lock: send_message(self.transport, req) self.process_server_ans(get_my_message(self.transport))
def user_list_update(self): logger.debug(f'Запрос списка известных пользователей {self.username}') req = { ACTION: USERS_REQUEST, TIME: time.time(), ACCOUNT_NAME: self.username } with socket_lock: send_message(self.transport, req) ans = get_my_message(self.transport) if RESPONSE in ans and ans[RESPONSE] == 202: self.database.add_users(ans[LIST_INFO]) else: logger.error('Не удалось обновить список известных пользователей.')
def remove_contact(sock, username, contact): LOGGER.debug(f'Создание контакта {contact}') req = { ACTION: REMOVE_CONTACT, TIME: time.time(), USER: username, ACCOUNT_NAME: contact } send_message(sock, req) ans = get_my_message(sock) if RESPONSE in ans and ans[RESPONSE] == 200: pass else: raise ServerError('Ошибка удаления клиента') print('Удачное удаление')
def send_message(self, to, message): message_dict = { ACTION: MESSAGE, SENDER: self.username, DESTINATION: to, TIME: time.time(), MESSAGE_TEXT: message } logger.debug(f'Сформирован словарь сообщения: {message_dict}') # Необходимо дождаться освобождения сокета для отправки сообщения with socket_lock: send_message(self.transport, message_dict) self.process_server_ans(get_my_message(self.transport)) logger.info(f'Отправлено сообщение для пользователя {to}')
def contacts_list_update(self): logger.debug(f'Запрос контакт листа для пользователся {self.name}') req = { ACTION: GET_CONTACTS, TIME: time.time(), USER: self.username } logger.debug(f'Сформирован запрос {req}') with socket_lock: send_message(self.transport, req) ans = get_my_message(self.transport) logger.debug(f'Получен ответ {ans}') if RESPONSE in ans and ans[RESPONSE] == 202: for contact in ans[LIST_INFO]: self.database.add_contact(contact) else: logger.error('Не удалось обновить список контактов.')
def run(self): while True: # Отдыхаем секунду и снова пробуем захватить сокет. # если не сделать тут задержку, то второй поток может достаточно # долго ждать освобождения сокета. time.sleep(1) with sock_lock: try: message = get_my_message(self.sock) except IncorrectDataRecivedError: LOGGER.error( f'Не удалось декодировать полученное сообщение.') except OSError as err: if err.errno: LOGGER.critical(f'Потеряно соединение с сервером.') break except (ConnectionError, ConnectionAbortedError, ConnectionResetError, json.JSONDecodeError): LOGGER.critical(f'Потеряно соединение с сервером.') break else: if ACTION in message and message[ACTION] == MESSAGE and SENDER in message and DESTINATION in message \ and MESSAGE_TEXT in message and message[DESTINATION] == self.account_name: print( f'\nПолучено сообщение от пользователя {message[SENDER]}:\n{message[MESSAGE_TEXT]}' ) # Захватываем работу с базой данных и сохраняем в неё # сообщение with database_lock: try: self.database.save_message( message[SENDER], self.account_name, message[MESSAGE_TEXT]) except BaseException: LOGGER.error( 'Ошибка взаимодействия с базой данных') LOGGER.info( f'Получено сообщение от пользователя {message[SENDER]}:\n{message[MESSAGE_TEXT]}' ) else: LOGGER.error( f'Получено некорректное сообщение с сервера: {message}' )
def connection_init(self, port, ip): # Инициализация сокета и сообщение серверу о нашем появлении self.transport = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Таймаут необходим для освобождения сокета. self.transport.settimeout(5) # Соединяемся, 5 попыток соединения, флаг успеха ставим в True если # удалось connected = False for i in range(2): logger.info(f'Попытка подключения №{i + 1}') try: self.transport.connect((ip, port)) except (OSError, ConnectionRefusedError): pass else: connected = True break time.sleep(1) # Если соединится не удалось - исключение if not connected: logger.critical('Не удалось установить соединение с сервером') raise ServerError('Не удалось установить соединение с сервером') logger.debug('Установлено соединение с сервером') # Посылаем серверу приветственное сообщение и получаем ответ что всё # нормально или ловим исключение. try: with socket_lock: send_message(self.transport, self.create_presence()) self.process_server_ans(get_my_message(self.transport)) except (OSError, json.JSONDecodeError): logger.critical('Потеряно соединение с сервером!') raise ServerError('Потеряно соединение с сервером!') # Раз всё хорошо, сообщение о установке соединения. logger.info('Соединение с сервером успешно установлено.')
def run(self): global new_connection self.init_socket() while True: # LOGGER.info(f'Waiting for client message') try: client, client_address = self.sock.accept() except OSError: pass else: LOGGER.info(f'Connection to {client_address} established ') self.clients.append(client) recv_data_lst = [] send_data_lst = [] err_lst = [] try: if self.clients: recv_data_lst, send_data_lst, err_lst = select.select( self.clients, self.clients, [], 0) except OSError as err: LOGGER.error(f'Ошибка работы с сокетами: {err}') # принимаем сообщения и если ошибка, исключаем клиента. if recv_data_lst: for client_with_message in recv_data_lst: try: self.process_client_message( get_my_message(client_with_message), client_with_message) except (OSError): # Ищем клиента в словаре клиентов и удаляем его из него # и базы подключённых LOGGER.info( f'Клиент {client_with_message.getpeername()} отключился от сервера.' ) for name in self.names: if self.names[name] == client_with_message: self.database.user_logout(name) del self.names[name] break self.clients.remove(client_with_message) with conflag_lock: new_connection = True # Если есть сообщения, обрабатываем каждое. for message in self.messages: try: self.process_message(message, send_data_lst) except (ConnectionAbortedError, ConnectionError, ConnectionResetError, ConnectionRefusedError): LOGGER.info( f'Связь с клиентом с именем {message[DESTINATION]} была потеряна' ) self.clients.remove(self.names[message[DESTINATION]]) self.database.user_logout(message[DESTINATION]) del self.names[message[DESTINATION]] with conflag_lock: new_connection = True self.messages.clear()
def main(): print('Client started') server_address, server_port, client_name = get_args() if not client_name: client_name = input('Введите имя пользователя: ') else: print(f'Клиентский модуль запущен с именем: {client_name}') LOGGER.info( f'Запущен клиент с парамертами: адрес сервера: {server_address} , порт: {server_port}, имя пользователя: {client_name}' ) try: transport = socket.socket(socket.AF_INET, socket.SOCK_STREAM) transport.settimeout(DEF_TIMEOUT) transport.connect((server_address, server_port)) send_message(transport, create_presence(client_name)) answer = process_response_ans(get_my_message(transport)) LOGGER.info( f'Установлено соединение с сервером. Ответ сервера: {answer}') print(f'Установлено соединение с сервером.') except json.JSONDecodeError: LOGGER.error('Не удалось декодировать полученную Json строку.') exit(1) except ServerError as error: LOGGER.error( f'При установке соединения сервер вернул ошибку: {error.text}') exit(1) except ReqFieldMissingError as missing_error: LOGGER.error( f'В ответе сервера отсутствует необходимое поле {missing_error.missing_field}' ) exit(1) except (ConnectionRefusedError, ConnectionError): LOGGER.critical( f'Не удалось подключиться к серверу {server_address}:{server_port}, конечный компьютер отверг запрос на подключение.' ) exit(1) else: database = ClientDB(client_name) database_load(transport, database, client_name) module_sender = ClientSender(client_name, transport, database) module_sender.daemon = True module_sender.start() LOGGER.debug('Запущены процессы') module_receiver = ClientReader(client_name, transport, database) module_receiver.daemon = True module_receiver.start() while True: time.sleep(1) if module_receiver.is_alive() and module_sender.is_alive(): continue break