TCP-сервер Python навсегда блокирует отправку клиенту, если клиент остановлен (SIGSTOP) - PullRequest
0 голосов
/ 12 марта 2019

У меня очень простой tcp сервер на python, код которого приведен ниже:

#!/usr/bin/env python                                                           

import socket

sock = socket.socket()

sock.bind(('',3912))
sock.listen(100)

num_cons = 10
cons = []
for i in range(num_cons):
    con, addr = sock.accept()
    cons.append(con)

while True:
    for con in cons:
        msg = "a"* 1000
        num_sent = con.send(msg.encode())
        print("sent: {} bytes of msg:{}".format(str(num_sent), msg))

Соответствующий код клиента

#!/usr/bin/env python                                                           

import socket

sock = socket.socket()

sock.connect(('',3912)) # in reality here I use the IP of the host where 
# I run the server since I launch the clients on a different host

while True:
    data = sock.recv(1000)
    print("received data: {} ".format(str(data)))

Теперь, если я запускаю сервер с

./server.py

и 10 клиентов параллельно с другого хоста:

for i in `seq 1 10`; do ./client.py 2>/dev/null 1>/dev/null & done

И я отправляю kill -SIGSTOP %1 первому клиенту, я ожидаю, что сервер успешно продолжит попытки отправки данных, потому что он не может знать, что клиент был остановлен. Вместо этого сервер блокируется, когда он пытается отправить данные клиенту 1. Я могу понять поведение, если клиенты находились на том же хосте, что и сервер: мы пытались записать данные, но буферы ядра заполнены, поэтому мы блокируем сервер, но клиент никогда не читает, поэтому буфер никогда не освобождается. Однако, если клиенты находятся на другом компьютере, буферы ядра хоста сервера должны быть заполнены только временно, а затем ядро ​​должно отправить данные по сетевой карте и освободить их. Так почему мой сервер блокирует вызов send? Я не проверял, наблюдается ли такое же поведение при использовании другого языка (например, C)

Ответы [ 2 ]

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

Это странно, потому что 1000 символов - это маленький размер для TCP.У меня нет доступного компьютера с Linux, но на коробке FreeBSD я мог успешно отправить 130000 байт по TCP-соединению, где одноранговый узел был остановлен до того, как блокирует отправителя.И более 1000000 в Windows.

Но поскольку TCP является подключенным протоколом, вызов send будет блокирован, если он не сможет поставить в очередь свои данные, поскольку внутренняя очередь стека TCP заполнена.

0 голосов
/ 13 марта 2019

Суть вашей проблемы заключается в том, что вы создаете сокет SOCK_STREAM (то есть TCP), а затем внезапно завершаете работу клиента. Как обсуждалось в HOWTO по программированию сокетов Python , в этой ситуации ожидается зависание.

TCP - это надежный протокол, означающий, что каждый передаваемый пакет должен быть подтвержден. Если принимающая сторона мертва, отправитель заблокирует ожидание этого подтверждения. Попробуйте установить тайм-аут и посмотрите, поднимает ли ваш send значение socket.timeout после ожидаемого времени.

...