Повторное использование дескриптора сокета при сбое соединения - PullRequest
9 голосов
/ 10 февраля 2010

В моем клиентском коде я выполняю следующие шаги для подключения к сокету:

  1. Создание сокета

    sockDesc = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)  
    
  2. Подключение (повторите попытку в течение времени 'x' в случае сбоя)

    connect(sockDesc, (sockaddr *) &destAddr, sizeof(destAddr))  
    

    (после заполнения полей destAddr)

  3. Использование сокета для операции send() / recv():

    send(sockDesc, buffer, bufferLen, 0)  
    recv(sockDesc, buffer, bufferLen, 0)  
    
  4. close() дескриптор сокета и выход

    close(sockDesc)  
    

Если во время send() / recv() соединение разрывается, я обнаружил, что могу подключиться, вернувшись к шагу 2.

Это решение хорошо? я должен закрыть дескриптор сокета и вернуться к шагу 1?

Другое интересное наблюдение, которое я не могу понять, это когда Я останавливаю свой эхо-сервер и запускаю клиент. Я создаю сокет (шаг 1) и вызываю connect(), что не удается (как и ожидалось), но затем я продолжаю звонить connect(), скажем, 10 раз. После 5 попыток я запускаю сервер, и connect() успешно. Но во время вызова send() он получает ошибку SIGPIPE. Я хотел бы знать:

1) Нужно ли создавать новый сокет каждый раз, когда connect() выходит из строя? Насколько я понимаю, пока я не выполнил send() / recv() для сокета, он так же хорош, как новый, и я могу повторно использовать тот же fd для вызова connect().

2) Я не понимаю, почему SIGPIPE получено при работающем сервере и connect() успешно.

Ответы [ 5 ]

5 голосов
/ 10 февраля 2010

Да, вы должны закрыть и вернуться к шагу 1:

close () закрывает дескриптор файла, так что это больше не относится к любому файл и может быть использован повторно.

С здесь .

4 голосов
/ 11 февраля 2010

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

Гнездо, которое не удалось подключить, может находиться не в том же состоянии, что и совершенно новое, - что может вызвать проблемы позже. Я предпочел бы избежать возможности и просто сделать новую. Это чище.

Сокеты TCP содержат много состояний, некоторые из которых зависят от реализации и разрабатываются из сети.

4 голосов
/ 10 февраля 2010

Розетки, соответствующие разорванному соединению, находятся в нестабильном состоянии. обычно вам не разрешат подключиться снова, если операционная система не освободит сокет.

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

В любом случае, обязательно установите LINGER вашего сокета, чтобы гарантировать, что данные не будут потеряны при передаче.

См. http://www.gnu.org/s/libc/manual/html_node/Socket_002dLevel-Options.html#Socket_002dLevel-Options

2 голосов
/ 11 февраля 2010

Если в спецификации Single UNIX не сказано, что она ДОЛЖНА работать, чтобы вернуться к шагу № 2 вместо шага № 1, то тот факт, что она работает в Linux, - это просто деталь реализации, и вам будет далеко лучше и более портативным, если вы вернетесь к шагу № 1. Насколько мне известно, спецификация не дает никаких гарантий того, что можно вернуться к шагу № 2, и поэтому я бы посоветовал вам вернуться к шагу № 1.

2 голосов
/ 10 февраля 2010

Если соединение было разорвано и вы пытаетесь записать в файловый дескриптор, вы должны получить ошибку / сигнал о разорванном канале. Все это говорит о том, что дескриптор файла, в который вы пытались записать, больше не имеет никого на другой стороне, чтобы прочитать то, что вы отправляете.

Что вы можете сделать, это перехватить сигнал SIGPIPE и затем выполнить повторное подключение, закрыв FD и вернувшись к шагу 1. Теперь у вас будет новый FD, который вы можете читать и записывать для соединения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...