Нужна помощь в мгновенной отправке моего сокетного мессенджера на Python

Я уверен, что есть более простые способы с определенными модулями Python, но для назначения мне нужно создать программу, которая может выступать в роли клиента / сервера. На данный момент у меня это работает до такой степени, что я могу отправить сообщение, только если получатель ответил. Мне нужно просто отправить и появиться на соответствующем клиент / серверном терминале при нажатии Enter. Любая помощь будет принята с благодарностью!

Это фотографии того, что происходит на данный момент

import sys
import socket
import getopt

def usage(script_name):
    print('Usage: py' + script_name + '-l' +' <port number>' + '[<server>]')

def sockObj():
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    return sock

def serversockConn(serversocket,port):
    serversocket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
    # bind the serversocket to address
    serversocket.bind(('',int(port)))
    # enable a server to accept connections
    serversocket.listen(5)
    # wait for a connection and accept it
    sock,addr = serversocket.accept()
    return sock

def connToServersock(sock,server, port):
    # connect to a serversocket
    if server:
        sock.connect((server, int(port)))
    else:
        sock.connect(('localhost', int(port)))
    return sock

if __name__ == '__main__':
    ## get the command line arguments
    try:
        options, non_option_args = getopt.getopt(sys.argv[1:],'l')
    except getopt.GetoptError as err:
        print(err)
        sys.exit(2)

    #check if '-l' is present in command line agrument
    serverSide = False
    for opt,arg in options:
        if opt == "-l":
            serverSide = True

    # port number
    port = non_option_args[0]

    # server address
    server = None
    hostLen = len(non_option_args)
    if hostLen == 2:
        server = non_option_args[1]


    # create a communicator object, and make a connection between server and client

    # server
    if serverSide:
        serversocket = sockObj()
        sock = serversockConn(serversocket,port)
    # client
    else:
        sock = sockObj()
        sock = connToServersock(sock,server,port)

    while True:
        ## read a message from standard input
        message = sys.stdin.readline().encode()
        if len(message) != 0:
            sock.send(message)
            return_msg = sock.recv( 1024 )
            if return_msg:
                print("Message recieved: " + return_msg.decode())
            else:
                print("Other side shut down")
        else:
            try:
                sock.shutdown(socket.SHUT_WR)
                sock.close()
            except:
                pass

1 ответ

Я думаю, что ваша проблема в том, что в вашем цикле событий есть два места, где вы блокируете:

    message = sys.stdin.readline().encode()

Здесь вы блокируете до тех пор, пока пользователь не нажмет кнопку возврата - в течение этого времени ваша программа не сможет отвечать на любые данные, полученные по сети, потому что она заблокирована в ожидании данных от стандартного ввода.

... а также:

        return_msg = sock.recv( 1024 )

Здесь вы ожидаете получения данных из сети - в течение этого времени ваша программа не может отвечать на любые данные, полученные от stdin, потому что она заблокирована в ожидании данных из сети.

В идеале вы хотели бы, чтобы ваша программа ожидала как стандартного, так и сетевого трафика одновременно - то есть блокировала его до тех пор, пока пользователь не нажмет return, или не будут получены некоторые сетевые данные, в зависимости от того, что наступит раньше.

Самый простой способ добиться такого поведения - использовать select(); его цель - блокировать, пока хотя бы один из нескольких файловых дескрипторов не будет готов к действию. (Обратите внимание, однако, что Windows не поддерживает использование select() на stdin, поэтому, если ваша программа должна работать под Windows, вам, вероятно, придется вместо этого создавать второй поток).

Для реализации цикла событий используется select(), добавлять import select в начало вашего скрипта, затем замените цикл обработки событий на что-то вроде этого:

while True:
    ## block here until either sock or sys.stdin has data ready for us
    readable, writable, exceptional = select.select([sock, sys.stdin], [], [])

    if sys.stdin in readable:
        ## read a message from standard input
        message = sys.stdin.readline().encode()
        if len(message) != 0:
            sock.send(message)

    if sock in readable:
        ## read a message from the network
        try:
            return_msg = sock.recv( 1024 )
            if (return_msg):
               print("Message received: " + return_msg.decode())
            else:
               print("Other side shut down")
               break
        except:
            print("recv() threw an exception")
            break
Другие вопросы по тегам