Повторное использование дескриптора сокета при сбое соединения
в моем клиентском коде я выполняю следующие шаги для подключения к сокету:
-
создание сокета
sockDesc = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)
-
подключение (повторите попытку в течение времени " x " в случае сбоя)
connect(sockDesc, (sockaddr *) &destAddr, sizeof(destAddr))
(после заполнения
destAddr
поля) -
использование сокета для
send()
/recv()
работы:send(sockDesc, buffer, bufferLen, 0) recv(sockDesc, buffer, bufferLen, 0)
-
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.