2016-03-21 5 views
0

У меня есть небольшой HTTP-сервер, написанный с использованием gevent, который принимает входящие соединения и отправляет обратно данные с помощью отдельной консоли. Когда (локальный) клиент умирает на стороне сервера пишет клиенту удается, несмотря на сокет, находясь в состоянии CLOSE_WAIT:gevent tcp socket отключен, но может отправлять данные

$ ls -l /proc/21860/fd |grep 22 
lrwx------. 1 mathieu mathieu 64 Mar 21 19:55 22 -> socket:[187093] 
$ lsof |grep 187093 
python 21860  mathieu 22u  IPv4    187093  0t0  TCP localhost.localdomain:36072->localhost.localdomain:48908 (CLOSE_WAIT) 

Теперь, я ожидал бы метод отправки сокета, я создал с gevent.socket.socket сбой с исключением, но я не получаю!

def send(socket, data): 
    sent = socket.send(data) 
    while sent != len(data): 
     data = data[sent:] 
     sent = socket.send(data) 

Является ли мое ожидание неправильным? Если нет, что здесь может быть неправильным?

ответ

0

После небольшой отладки выяснилось, что мое ожидание о том, как работает API-интерфейс сокета поверх TCP, неверно. Потенциальные читатели могли бы хотеть читать внимательно TCP option SO_LINGER (zero) - when it's required

вещи забрать:

  1. стороны клиента близко() посылает FIN на сервер, который примерно означает «Я закончил передачу вам данные». Это означает, что сервер все равно сможет отправлять обратно данные.
  2. Если сервер пытается написать после закрытия на стороне клиента, запись будет успешной (возвращает количество байтов, скопированных из пользовательского пространства в ядерное пространство), данные будут отправлены клиенту, клиент отправит обратно RST, поскольку его сокет все еще находится в состоянии TIMEWAIT (если вы не отключили это с помощью SO_LINGER ноль, поэтому вы действительно не хотите, чтобы SO_LINGER равнялся нулю), состояние сокета сервера будет обновлено до ЗАКРЫТО.
  3. Если сервер пытается выполнить вторую запись после получения RST от клиента, запись не будет выполнена.
  4. Если сервер пытается получить recv после закрытия на стороне клиента, recv вернет ноль, чтобы указать конец потока.

Чтобы подвести итог, это означает, что моему серверу необходимо использовать уведомление о конце потока, возвращаемое как recv() == 0, как знак того, что клиент закрыл свое соединение и действует соответствующим образом (то есть , закройте соответствующий сокет).