Сообщить об ошибке.

Классы Datagram/Stream RequestHandler модуля socketserver в Python

Обработчики запросов клиентов, использующие файловый интерфейс

Синтаксис:

import socketserver

socketserver.StreamRequestHandler
socketserver.DatagramRequestHandler

Описание:

Классы StreamRequestHandler и DatagramRequestHandler представляют собой подклассы BaseRequestHandler, которые переопределяют методы setup() и finish() и предоставляют атрибуты self.rfile и self.wfile.

Атрибуты self.rfile и self.wfile позволяют получить данные запроса или вернуть данные клиенту соответственно.

Атрибуты .rfile обоих классов поддерживают интерфейс io.BufferedIOBase доступный для чтения, а метод .wfile обоих классов поддерживает интерфейс, доступный для записи.

Изменено в Python 3.6: Метод StreamRequestHandler.wfile также стал поддерживать доступный для записи интерфейс io.BufferedIOBase.

Обычно, чтобы реализовать службу, необходимо сначала наследоваться от класса BaseRequestHandler, что бы создать пользовательский обработчик запросов, переопределив метод .handle(). Затем, уже можно запускать различные версии службы, объединив один из классов сервера с созданным классом обработчика запросов.

Для служб datagram или stream класс обработчика запросов должен быть другим. Это различие можно скрыть с помощью подклассов обработчиков StreamRequestHandler или DatagramRequestHandler.

Пример обработчика запросов, который использует файловый интерфейс:

Файлоподобные объекты, упрощающие обмен данными за счет предоставления стандартного файлового интерфейса.

В классе, привеенном ниже, вызов метода .readline() будет автоматически вызывать метод объекта сокета Socket.recv() несколько раз, пока не встретит символ новой строки.

Серверная сторона:

# server.py
import socketserver

class MyTCPHandler(socketserver.StreamRequestHandler):
    """
    Класс обработчика запросов для сервера.
    Он создается один раз при каждом подключении к серверу и должен
    Переопределить метод `handle()` для реализации связи с клиентом.
    """

    def handle(self):
        # self.rfile - это файловый объект, созданный обработчиком;
        # теперь можем использовать, например, `.readline()` 
        # вместо необработанных вызовов метода сокета `.recv()`
        self.data = self.rfile.readline().strip()
        print(f"{self.client_address[0]} прислал:")
        data = self.data.decode("utf-8")
        print(data)        
        # Аналогично, `self.wfile` - это файлоподобный объект, 
        # используемый для обратной отправки сообщения клиенту
        self.wfile.write(data.upper().encode("utf-8"))

if __name__ == "__main__":
    HOST, PORT = "localhost", 9999
    # Создаем сервер, привязанный к `localhost` на порту 9999
    with socketserver.TCPServer((HOST, PORT), MyTCPHandler) as server:
        # Активируем сервер. Работа будет продолжаться до тех пор, 
        # пока не прервать программу при помощи Ctrl-C
        server.serve_forever()

Что бы проверить работу сервера, используйте следующий код клиентской стороны или напишите свой. Первым запускается серверная сторона. Клиент запускается в другом терминале. Сообщение клиенту формируется как параметр командной строки при запуске клиентского скрипта, например $ python3 client.py Hello world!

import socket, sys

HOST, PORT = "localhost", 9999
# Данные для отправки получим 
# как параметры командной строки
data = " ".join(sys.argv[1:])

# Создаем сокет (`SOCK_STREAM` означает сокет TCP)
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
    # Подключение к серверу и отправка данных
    sock.connect((HOST, PORT))
    sock.sendall(bytes(data + "\n", "utf-8"))

    # Получаем данные с сервера и завершаем работу
    received = str(sock.recv(1024), "utf-8")

print(f"Отправлено: {data}")
print(f"Получено: {received}")