Нужна помощь в мгновенной отправке моего сокетного мессенджера на Python - PullRequest
0 голосов
/ 02 февраля 2019

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

Это фотографии того, что происходит сейчас https://i.stack.imgur.com/T9CsJ.png

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 Ответ

0 голосов
/ 02 февраля 2019

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

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

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

... и:

        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
...