Повторное использование дескриптора сокета при сбое соединения
в моем клиентском коде я выполняю следующие шаги для подключения к сокету:
-
создание сокета
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.