使用套接字和选择模块的Python2.7聊天(非阻塞代码)

时间:2019-03-26 15:37:23

标签: python python-2.7 sockets select networking

嗨,我有一个练习,要使用套接字选择和msvcrt,服务器和mltiplie chat(服务器和客户端需要无阻塞地构建)的客户端进行构建,每个客户端都将发送消息,服务器将消息发送至除了发送邮件的那个服务器以外的所有客户端:

import socket
import select


IP = "192.168.1.154"
port = 123
default_buffer_size = 1024
open_client_sockets = []
messages_to_send = []


def send_waiting_messages(wlist):

    for message in messages_to_send:
        (client_sock, data) = message
        if client_sock in wlist:
            for sock in open_client_sockets:
                if sock is not client_sock:
                    sock.send(data)
            messages_to_send.remove(message)


def main():

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind((IP, port))
    sock.listen(5)
    print("The server is on and waiting for client...")
    while True:
        rlist, wlist, xlist = select.select([sock] + open_client_sockets, open_client_sockets, [])
        for current_socket in rlist:
            if current_socket is sock:
                (new_socket, addr) = sock.accept()
                open_client_sockets.append(new_socket)
            else:
                data = current_socket.recv(default_buffer_size)
                if data == "":
                    open_client_sockets.remove(current_socket)
                    print("Connection with client closed")
                else:
                    messages_to_send.append((current_socket, 'Hello ' + data))
        send_waiting_messages(wlist)


if __name__ == '__main__':
    main()

构建服务器并非难事,因为本书对此进行了指导(如果没有进行指导,我将永远无法使这段代码正常工作),但是构建客户端存在问题,主要原因是我不了解{{1} }正常工作,找不到答案可以为我简化此模块。 这是我对客户所做的:

select.select

这可能表明您对模块选择和练习并不了解。我看到一些线程也有类似的问题,但是我对它们一无所知,因此我确实需要很好的移植。 总之,我真的迷路了……

1 个答案:

答案 0 :(得分:1)

select将等待可读性的套接字列表,等待可写性的套接字列表以及等待错误的套接字列表作为参数。它返回准备读,准备写和错误套接字的列表。来自帮助:

>>> help(select.select)
Help on built-in function select in module select:

select(...)
    select(rlist, wlist, xlist[, timeout]) -> (rlist, wlist, xlist)

    Wait until one or more file descriptors are ready for some kind of I/O.
    The first three arguments are sequences of file descriptors to be waited for:
    rlist -- wait until ready for reading
    wlist -- wait until ready for writing
    xlist -- wait for an ``exceptional condition''
    If only one kind of condition is required, pass [] for the other lists.
    A file descriptor is either a socket or file object, or a small integer
    gotten from a fileno() method call on one of those.

    The optional 4th argument specifies a timeout in seconds; it may be
    a floating point number to specify fractions of seconds.  If it is absent
    or None, the call will never time out.

    The return value is a tuple of three lists corresponding to the first three
    arguments; each contains the subset of the corresponding file descriptors
    that are ready.

    *** IMPORTANT NOTICE ***
    On Windows, only sockets are supported; on Unix, all file
    descriptors can be used.

因此,要修复客户端,您需要将打开的套接字(sock)添加到sockets列表中。如果准备好编写套接字,则可以调用write函数。

write中,使用msvcrt.kbhit()测试键入的字符。您不能只使用input,因为它会阻塞。然后,如果已键入字符,则读取该字符。收集字符,直到您按下enter,然后生成一条消息并将其写入套接字。像这样:

message = []

def write(sock):
    if msvcrt.kbhit():
        c = msvcrt.getche()
        if c == '\r':
            data = ''.join(message)
            print 'sending:',data
            sock.sendall(data)
            message.clear()
        else:
            message.append(c)