Example #1
0
class Server(threading.Thread, metaclass=ServerMaker):
    port = Port()

    def __init__(self, listen_address, listen_port, database):
        self.addr = listen_address
        self.port = listen_port

        self.database = database
        self.clients = []

        self.messages = []

        self.names = dict()

        super().__init__()

    def init_socket(self):
        logger.info(
            f'Запущен сервер, с портом: {self.port} , адрес с которого принимаются подключения: {self.addr}. Если адрес не указан, принимаются соединения с любых адресов.')
        # Готовим сокет
        forward = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        forward.bind((self.addr, self.port))
        forward.settimeout(0.5)

        # Начинаем слушать сокет.
        self.sock = forward
        self.sock.listen()

    def run(self):
        self.init_socket()

        while True:
            try:
                client, client_address = self.sock.accept()
            except OSError:
                pass
            else:
                logger.info(f'Установлено соедение с ПК {client_address}')
                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:
                pass

            if recv_data_lst:
                for client_with_message in recv_data_lst:
                    try:
                        self.handling_mess_from_client(rec_message(client_with_message), client_with_message)
                    except:
                        logger.info(f'Клиент {client_with_message.getpeername()} отключился от сервера.')
                        self.clients.remove(client_with_message)

            for message in self.messages:
                try:
                    self.process_message(message, send_data_lst)
                except:
                    logger.info(f'Связь с клиентом с именем {message[DESTINATION]} была потеряна')
                    self.clients.remove(self.names[message[DESTINATION]])
                    del self.names[message[DESTINATION]]
            self.messages.clear()

    def process_message(self, message, listen_socks):
        """
        Отправка сообщения конкретному пользователю
        :param message:
        :param names:
        :param listen_socks:
        :return:
        """
        if message[DESTINATION] in self.names and self.names[message[DESTINATION]] in listen_socks:
            transmit_message(self.names[message[DESTINATION]], message)
            logger.info(f'Отправлено сообщение пользователю {message[DESTINATION]} '
                        f'от пользователя {message[SENDER]}.')
        elif message[DESTINATION] in self.names and self.names[message[DESTINATION]] not in listen_socks:
            raise ConnectionError
        else:
            logger.error(
                f'Пользователь {message[DESTINATION]} не зарегистрирован на сервере, '
                f'отправка сообщения невозможна.')

    def handling_mess_from_client(self, message, client):
        """
        Обработка сообщения от клиента в виде словаря,
        проверка и отправка ответа.
        :param message:
        :param messages_list:
        :param client:
        :param clients:
        :param names:
        :return:
        """
        logger.debug(f'Разбор сообщения от клиента : {message}')
        # Если это сообщение presence получаем и отвечаем
        if ACTION in message and message[ACTION] == PRESENCE and \
                TIME in message and USER in message:
            # Регистрация пользователя если он ещё не зареган
            #  иначе  завершаем соединение.
            if message[USER][ACCOUNT_NAME] not in self.names.keys():
                self.names[message[USER][ACCOUNT_NAME]] = client
                client_ip, client_port = client.getpeername()
                self.database.user_login(message[USER][ACCOUNT_NAME], client_ip, client_port)
                transmit_message(client, RESPONSE_200)
            else:
                response = RESPONSE_400
                response[ERROR] = 'Выберите другое имя - это уже занято.'
                transmit_message(client, response)
                self.clients.remove(client)
                client.close()
            return
        # Добавляем в очередь на ответ
        elif ACTION in message and message[ACTION] == MESSAGE and \
                DESTINATION in message and TIME in message \
                and SENDER in message and MESSAGE_TEXT in message:
            self.messages.append(message)
            return
        # Если клиент выходит
        elif ACTION in message and message[ACTION] == EXIT and ACCOUNT_NAME in message:
            self.database.user_logout(message[ACCOUNT_NAME])
            self.clients.remove(self.names[ACCOUNT_NAME])
            self.names[ACCOUNT_NAME].close()
            del self.names[ACCOUNT_NAME]
            return
        else:
            response = RESPONSE_400
            response[ERROR] = 'Запрос некорректен.'
            transmit_message(client, response)
            return
Example #2
0
class Server(metaclass=ServerMaker):
    port = Port()

    def __init__(self, listen_address, listen_port):
        # Параментры подключения
        self.addr = listen_address
        self.port = listen_port

        # Список подключённых клиентов.
        self.clients = []

        # Список сообщений на отправку.
        self.messages = []

        # Словарь содержащий сопоставленные имена и соответствующие им сокеты.
        self.names = dict()

    def init_socket(self):
        logger.info(
            f'Запущен сервер, порт для подключений: {self.port} , адрес с которого принимаются подключения: {self.addr}. Если адрес не указан, принимаются соединения с любых адресов.'
        )
        # Готовим сокет
        transport = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        transport.bind((self.addr, self.port))
        transport.settimeout(0.5)

        # Начинаем слушать сокет.
        self.sock = transport
        self.sock.listen()

    def main_loop(self):
        # Инициализация Сокета
        self.init_socket()

        # Основной цикл программы сервера
        while True:
            # Ждём подключения, если таймаут вышел, ловим исключение.
            try:
                client, client_address = self.sock.accept()
            except OSError:
                pass
            else:
                logger.info(f'Установлено соедение с ПК {client_address}')
                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:
                pass

            # принимаем сообщения и если ошибка, исключаем клиента.
            if recv_data_lst:
                for client_with_message in recv_data_lst:
                    try:
                        self.process_client_message(
                            get_message(client_with_message),
                            client_with_message)
                    except:
                        logger.info(
                            f'Клиент {client_with_message.getpeername()} отключился от сервера.'
                        )
                        self.clients.remove(client_with_message)

            # Если есть сообщения, обрабатываем каждое.
            for message in self.messages:
                try:
                    self.process_message(message, send_data_lst)
                except:
                    logger.info(
                        f'Связь с клиентом с именем {message[DESTINATION]} была потеряна'
                    )
                    self.clients.remove(self.names[message[DESTINATION]])
                    del self.names[message[DESTINATION]]
            self.messages.clear()

    # Функция адресной отправки сообщения определённому клиенту. Принимает словарь сообщение, список зарегистрированых
    # пользователей и слушающие сокеты. Ничего не возвращает.
    def process_message(self, message, listen_socks):
        if message[DESTINATION] in self.names and self.names[
                message[DESTINATION]] in listen_socks:
            send_message(self.names[message[DESTINATION]], message)
            logger.info(
                f'Отправлено сообщение пользователю {message[DESTINATION]} от пользователя {message[SENDER]}.'
            )
        elif message[DESTINATION] in self.names and self.names[
                message[DESTINATION]] not in listen_socks:
            raise ConnectionError
        else:
            logger.error(
                f'Пользователь {message[DESTINATION]} не зарегистрирован на сервере, отправка сообщения невозможна.'
            )

    # Обработчик сообщений от клиентов, принимает словарь - сообщение от клиента, проверяет корректность, отправляет
    #     словарь-ответ в случае необходимости.
    def process_client_message(self, message, client):
        logger.debug(f'Разбор сообщения от клиента : {message}')
        # Если это сообщение о присутствии, принимаем и отвечаем
        if ACTION in message and message[
                ACTION] == PRESENCE and TIME in message and USER in message:
            # Если такой пользователь ещё не зарегистрирован, регистрируем, иначе отправляем ответ и завершаем соединение.
            if message[USER][ACCOUNT_NAME] not in self.names.keys():
                self.names[message[USER][ACCOUNT_NAME]] = client
                send_message(client, RESPONSE_200)
            else:
                response = RESPONSE_400
                response[ERROR] = 'Имя пользователя уже занято.'
                send_message(client, response)
                self.clients.remove(client)
                client.close()
            return
        # Если это сообщение, то добавляем его в очередь сообщений. Ответ не требуется.
        elif ACTION in message and message[ACTION] == MESSAGE and DESTINATION in message and TIME in message \
                and SENDER in message and MESSAGE_TEXT in message:
            self.messages.append(message)
            return
        # Если клиент выходит
        elif ACTION in message and message[
                ACTION] == EXIT and ACCOUNT_NAME in message:
            self.clients.remove(self.names[ACCOUNT_NAME])
            self.names[ACCOUNT_NAME].close()
            del self.names[ACCOUNT_NAME]
            return
        # Иначе отдаём Bad request
        else:
            response = RESPONSE_400
            response[ERROR] = 'Запрос некорректен.'
            send_message(client, response)
            return
Example #3
0
class Server(metaclass=ServerMaker):
    port = Port()

    def __init__(self, listen_addr, listen_port):
        self.addr = listen_addr
        self.port = listen_port
        self.clients = []
        self.messages = []
        self.names = dict()

    def init_socket(self):
        LOG.info(
            f"Запущен сервер, порт для подключений: {self.port} , "
            f"адрес с которого принимаются подключения: {self.addr}."
            f"Если адрес не указан, принимаются соединения с любых адресов.")

        transport = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        transport.bind((self.addr, self.port))
        transport.settimeout(0.5)
        self.sock = transport
        self.sock.listen()

    def main_loop(self):
        self.init_socket()

        while True:
            try:
                client, client_address = self.sock.accept()
            except OSError:
                pass
            else:
                LOG.info(f"Установлено соедение с ПК {client_address}")
                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:
                pass

            if recv_data_lst:
                for client_with_message in recv_data_lst:
                    try:
                        self.client_message_handler(
                            MSG.get(client_with_message), client_with_message)
                    except:
                        LOG.info(
                            f"Клиент {client_with_message.getpeername()} отключился от сервера."
                        )
                        self.clients.remove(client_with_message)
            for message in self.messages:
                try:
                    self.process_message(message, send_data_lst)
                except:
                    LOG.info(
                        f"Связь с клиентом с именем {message[s.KEY_TO]} была потеряна"
                    )
                    self.clients.remove(self.names[message[s.KEY_TO]])
                    del self.names[message[s.KEY_TO]]
            self.messages.clear()

    def process_message(self, message, listen_socks):
        if (message[s.KEY_TO] in self.names
                and self.names[message[s.KEY_TO]] in listen_socks):
            MSG.send(self.names[message[s.KEY_TO]], message)
            LOG.info(
                f"Отправлено сообщение пользователю {message[s.KEY_TO]} от пользователя {message[s.KEY_FROM]}."
            )
        elif (message[s.KEY_TO] in self.names
              and self.names[message[s.KEY_TO]] not in listen_socks):
            raise ConnectionError
        else:
            LOG.error(
                f"Пользователь {message[s.KEY_TO]} не зарегистрирован на сервере, отправка сообщения невозможна."
            )

    def client_message_handler(self, message, client):
        """
        Message handler from clients, accepts dictionary -
        message from the client, checks correctness,
        returns the response dictionary for the client

        """
        LOG.debug(f"Разбираем сообщение: {message}")
        if (s.KEY_ACTION in message
                and message[s.KEY_ACTION] == s.ACTION_PRESENCE
                and s.KEY_TIME in message and s.KEY_USER in message):
            if message[s.KEY_USER][
                    s.KEY_ACCOUNT_NAME] not in self.names.keys():
                self.names[message[s.KEY_USER][s.KEY_ACCOUNT_NAME]] = client
                MSG.send(client, s.RESPONSE_200)
            else:
                response = s.RESPONSE_400
                response[s.KEY_ERROR] = "Имя пользователя уже занято."
                MSG.send(client, response)
                self.clients.remove(client)
                client.close()
            return
        # Если это сообщение, то добавляем его в очередь сообщений.
        # Ответ не требуется.
        elif (s.KEY_ACTION in message
              and message[s.KEY_ACTION] == s.ACTION_MESSAGE
              and s.KEY_TIME in message and s.KEY_TO in message
              and s.KEY_FROM in message and s.KEY_MESSAGE in message):
            self.messages.append(message)
            return
        # Если клиент выходит
        elif (s.KEY_ACTION in message
              and message[s.KEY_ACTION] == s.ACTION_EXIT
              and s.KEY_ACCOUNT_NAME in message):
            self.clients.remove(self.names[message[s.KEY_ACCOUNT_NAME]])
            self.names[message[s.KEY_ACCOUNT_NAME]].close()
            del self.names[message[s.KEY_ACCOUNT_NAME]]
            return
        # Иначе отдаём Bad request
        else:
            response = s.RESPONSE_400
            response[s.KEY_ERROR] = "Запрос не корректен"
            MSG.send(client, response)
            return