Чат Python2.7 с использованием сокетов и модуля выбора (неблокирующий код) - PullRequest
0 голосов
/ 26 марта 2019

Привет, у меня есть упражнение по сборке с использованием сокетов select и 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()

Сборка сервера не была трудной, потому что он руководствовался (если бы я не руководствовался, я бы никогда не получил этот код работающим) книгой, но у меня проблема со сборкой клиента, и главная причина в том, что я не понимаю, как работает select.select , не смог найти ответ, который достаточно упростит этот модуль для меня. вот что я сделал с клиентом:

import socket
import select
import msvcrt

IP = "192.168.1.154"
port = 123


sockets = []


def write():
    pass


def main():
    sock = socket.socket()
    sock.connect((IP, port))
    while True:
        rlist, wlist, xlist = select.select(sockets, sockets, [])
        for current_socket in rlist:
            if current_socket is sock:
                data = current_socket.recv(1024)
                print(data)
            else:
                sockets.append(current_socket)
        write()


if __name__ == '__main__':
    main()

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

1 Ответ

1 голос
/ 28 марта 2019

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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...