Почему мне нужно нажимать ввод, чтобы увидеть ввод другого клиента на сервере сокета python?

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

Код сервера:

import socket
import select

HEADER_LENGTH = 10

IP = "127.0.0.1"
PORT = 1234

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)


server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)


server_socket.bind((IP, PORT))

server_socket.listen()

sockets_list = [server_socket]

clients = {}

print(f'Listening for connections on {IP}:{PORT}...')

def receive_message(client_socket):

    try:

        message_header = client_socket.recv(HEADER_LENGTH)

        if not len(message_header):
            return False

        message_length = int(message_header.decode('utf-8').strip())

        return {'header': message_header, 'data': client_socket.recv(message_length)}

    except:

        return False

while True:

    read_sockets, _, exception_sockets = select.select(sockets_list, [], sockets_list)


    for notified_socket in read_sockets:

        if notified_socket == server_socket:

            client_socket, client_address = server_socket.accept()


            user = receive_message(client_socket)

            if user is False:
                continue

            sockets_list.append(client_socket)

            clients[client_socket] = user

            print('Accepted new connection from {}:{}, username: {}'.format(*client_address, user['data'].decode('utf-8')))

        else:

            message = receive_message(notified_socket)

            if message is False:
                print('Closed connection from: {}'.format(clients[notified_socket]['data'].decode('utf-8')))

                sockets_list.remove(notified_socket)

                del clients[notified_socket]

                continue

            user = clients[notified_socket]

            print(f'Received message from {user["data"].decode("utf-8")}: {message["data"].decode("utf-8")}')

            for client_socket in clients:

                if client_socket != notified_socket:

                    client_socket.send(user['header'] + user['data'] + message['header'] + message['data'])

    for notified_socket in exception_sockets:

        sockets_list.remove(notified_socket)

        del clients[notified_socket]

Код клиента:

import socket
import select
import errno
import sys

HEADER_LENGTH = 10

IP = "127.0.0.1"
PORT = 1234
my_username = input("Username: ")

client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

client_socket.connect((IP, PORT))

client_socket.setblocking(False)

username = my_username.encode('utf-8')
username_header = f"{len(username):<{HEADER_LENGTH}}".encode('utf-8')
client_socket.send(username_header + username)

while True:

    message = input(f'{my_username} > ')
    if message:

        message = message.encode('utf-8')
        message_header = f"{len(message):<{HEADER_LENGTH}}".encode('utf-8')
        client_socket.send(message_header + message)

    try:
        while True:

            username_header = client_socket.recv(HEADER_LENGTH)

            if not len(username_header):
                print('Connection closed by the server')
                sys.exit()

            username_length = int(username_header.decode('utf-8').strip())

            username = client_socket.recv(username_length).decode('utf-8')

            message_header = client_socket.recv(HEADER_LENGTH)
            message_length = int(message_header.decode('utf-8').strip())
            message = client_socket.recv(message_length).decode('utf-8')

            print(f'{username} > {message}')

    except IOError as e:

        if e.errno != errno.EAGAIN and e.errno != errno.EWOULDBLOCK:
            print('Reading error: {}'.format(str(e)))
            sys.exit()

        continue

    except Exception as e:
        print('Reading error: '.format(str(e)))
        sys.exit()
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
264
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Когда вы вызываете input() любого вида, который блокирует поток. Таким образом, вам придется ждать input(), чтобы получить recv() сообщение с сервера. Как правило, вы решаете эту проблему с помощью многопоточности. Использование дополнительного потока для печати сообщений на вашем клиенте во время прослушивания input().

Например:

import socket
import threading
import sys

def recieve_thread():
    #recieve the messages from the server by starting a new thread
    running = True
    while running == True:
            username_header = client_socket.recv(HEADER_LENGTH)

            if not len(username_header):
                print('Connection closed by the server')
                sys.exit()

            username_length = int(username_header.decode('utf-8').strip())

            username = client_socket.recv(username_length).decode('utf-8')

            message_header = client_socket.recv(HEADER_LENGTH)
            message_length = int(message_header.decode('utf-8').strip())
            message = client_socket.recv(message_length).decode('utf-8')
            print(f'{username} > {message}')
 
thread = threading.Thread(target =recieve_thread)#if your function has arguments you can pass them as 'args =(arg,)'
thread.start() 

Еще одно замечание: вы всегда должны избегать бесконечных циклов. Как while True, так как ваш процесс будет работать вечно, если вы не используете диспетчер ОС, чтобы остановить его. Я изменил while True часть вашего кода и добавил управляющую переменную :running, чтобы вы могли остановить программу по определенной логике.

Я получил ошибку «Операция неблокирующего сокета не может быть завершена немедленно». Как это исправить?

oogabooga 24.12.2020 09:17

@oogabooga единственная причина, по которой вы установили для сокета значение client_socket.setblocking(False), заключалась в том, чтобы не блокировать основной поток, теперь вы можете удалить эту строку. Блокировка больше не будет проблемой, поскольку вы получаете и отправляете сообщения в двух разных потоках.

RonsJurisdiction 24.12.2020 09:37

@oogabooga неблокирующий сокет считывает данные (если они доступны), а если они недоступны, он генерирует исключение (то, которое вы получаете). Таким образом, вам нужно будет либо заблокировать, удалив ложный атрибут блокировки, либо бросить его в попытке, кроме и обработать его. проверить: stackoverflow.com/questions/15509245/…

RonsJurisdiction 24.12.2020 09:47

Другие вопросы по теме