Многие реализации после установления соединения округляют размер приемного буфера сокета в большую сторону, чтобы он было кратным MSS. Чтобы узнать размер приемного буфера сокета после установления соединения, можно исследовать пакеты с помощью программы типа
заставит TCP на стороне клиента прекратить работу путем отправки сегмента RST вместо нормального обмена четырьмя сегментами. Дочерний процесс сервера вызывает функцию
readline
, возвращает ошибку
ECONNRESET
и выводит следующее сообщение:
readline error: Connection reset by peer
Клиентский сокет не должен проходить через состояние ожидания TIME_WAIT, даже если клиент выполняет активное закрытие.
7.4. Первый клиент вызывает функции
setsockopt
,
bind
и
connect
. Но если второй клиент вызовет функцию
bind
между вызовами функций
bind
и
connect
первого клиента, возвращается ошибка
EADDRINUSE
. Но как только первый клиент установит соединение с собеседником, вызов функции
bind
второго клиента будет работать, поскольку сокет первого клиента уже присоединен. В случае возвращения ошибки
EADDRINUSE
второму клиенту следует вызывать
bind
несколько раз, а не останавливаться при появлении первой ошибки — это единственный способ справиться с данной ситуацией.
7.5. Запускаем программу на узле без поддержки многоадресной передачи (MacOS X 10.2.6).
macosx % sock -s 9999 &запускаем первый сервер с универсальным адресом
[1] 29697
macosx % sock -s 172.24.37.78 9999пробуем второй сервер, но без -А
can't bind local address: Address already in use
macosx % sock -s -A 172.24.37.78 9999 &пробуем опять с -A: работает
[2] 29699
macosx % sock -s -A 127.0.0.1 9999 &третий сервер с -A; работает
[3] 29700
macosx % netstat -na | grep 9999
tcp4 0 0 127.0.0.1.9999 *.* LISTEN
tcp4 0 0 206.62.226.37.9999 *.* LISTEN
tcp4 0 0 *.9999 *.* LISTEN
7.6. Теперь попробуем проделать то же на узле с поддержкой многоадресной передачи, но без поддержки параметра
SO_REUSEADDR
(Solaris 9).
solaris % sock -s -u 8888 &запускаем первый
[1] 24051
solaris % sock -s -u 8888
can't bind local address: Address already in use
solaris % sock -s -u -A 8888 &снова пробуем запустить второй с -A:
работает
solaris % netstat -na | grep 8888мы видим дублированное связывание
*.8888 Idle
* 8888 Idle
В этой системе задавать параметр
SO_REUSEADDR
было необходимо только для второго связывания. Наконец, запускаем сценарий в MacOS X 10.2.6, где поддерживается как многоадресная передача, так и параметр
SO_REUSEPORT
. Сначала пробуем использовать
SO_REUSEADDR
для обоих серверов, но это не работает.
macosx % sock -u -s -A 7777 &
[1] 17610
macosx % sock -u -s -A 7777
can't bind local address: Address already in use
Тогда пробуем использовать параметр
SO_REUSEPORT
только для второго сервера. Это также не работает, так как полностью дублированное связывание требует включения данного параметра для всех сокетов, совместно использующих соединение.
macosx % sock -u -s 8888 &
[1] 17612
macosx % sock -u -s -T 8888
can't bind local address: Address already in use
Наконец, задаем параметр
SO_REUSEPORT
для обоих серверов, и этот вариант работает.
macosx % sock -u -s -Т 9999 &
[1] 17614
macosx % sock -u -s -T 9999 &
[2] 17615
macosx % netstat -na | grep 9999
udp4 0 0 *.9999 *.*
udp4 0 0 *.9999 *.*
7.7. Этот параметр (
– d
) не делает ничего, поскольку программа
ping
использует ICMP-сокет, а параметр сокета
SO_DEBUG
влияет только на TCP-сокеты. Описание параметра сокета
SO_DEBUG
всегда было довольно расплывчатым, наподобие «этот параметр допускает отладку на соответствующем уровне протокола», и единственный уровень протокола, где реализуется данный параметр — это TCP.