Повторное использование дескриптора сокета при сбое соединения

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

  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 ответов


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

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

с здесь.


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

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

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

посмотреть http://www.gnu.org/s/libc/manual/html_node/Socket_002dLevel-Options.html#Socket_002dLevel-Options


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

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

TCP-сокеты содержат много состояний, некоторые из которых специфичны для реализации и разработаны из сети.


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

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


Если одна спецификация UNIX не говорит, что она должна работать, чтобы вернуться к Шагу #2 вместо шага #1, то тот факт, что она работает на Linux, - это просто деталь реализации, и вам было бы намного лучше и более переносимо, если вы вернетесь к шагу #1. Насколько мне известно, спецификация не гарантирует, что можно вернуться к Шагу № 2, и поэтому я бы посоветовал вам вернуться к шагу № 1.