Страница 385 из 399
Листинг Д.2. Вывод размера приемного буфера сокета и MSS до и после установления соединения
//sockopt/rcvbuf.c
1 #include "urp.h"
2 #include <netinet/tcp.h> /* для TCP_MAXSEG */
3 int
4 main(int argc, char **argv)
5 {
6 int sockfd, rcvbuf, mss;
7 socklen_t len;
8 struct sockaddr_in servaddr;
9 if (argc != 2)
10 err_quit("usage: rcvbuf <Ipaddress>");
11 sockfd = Socket(AF_INET, SOCK_STREAM, 0);
12 len = sizeof(rcvbuf);
13 Getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, &len);
14 len = sizeof(mss);
15 Getsockopt(sockfd, IPPROTO_TCP, TCP_MAXSEG, &mss, &len);
16 printf("defaults: SO_RCVBUF = %d. MSS = %dn", rcvbuf, mss);
17 bzero(&servaddr, sizeof(servaddr));
18 servaddr.sin_family = AF_INET;
19 servaddr.sin_port = htons(13); /* сервер времени и даты */
20 Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
21 Co
22 len = sizeof(rcvbuf);
23 Getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, &len);
24 len = sizeof(mss);
25 Getsockopt(sockfd, IPPROTO_TCP, TCP_MAXSEG, &mss, &len);
26 printf("after co
27 exit(0);
28 }
He существует какого-то одного «правильного» вывода для данной программы. Результаты зависят от системы. Некоторые системы (в особенности Solaris 2.5.1 и более ранние версии) всегда возвращают нулевой размер буфера сокета, не давая нам возможности увидеть, что происходит с этим значением в процессе соединения.
До вызова функции co
Многие реализации после установления соединения округляют размер приемного буфера сокета в большую сторону, чтобы он было кратным MSS. Чтобы узнать размер приемного буфера сокета после установления соединения, можно исследовать пакеты с помощью программы типа tcpdump и посмотреть, каков размер объявленного окна TCP.
7.3. Разместите в памяти структуру linger по имени ling и проинициализируйте ее следующим образом:
str_cli(stdin, sockfd);
ling.l_onoff = 1;
ling.l_linger = 0;
Setsockopt(sockfd, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling));
exit(0);
Это заставит TCP на стороне клиента прекратить работу путем отправки сегмента RST вместо нормального обмена четырьмя сегментами. Дочерний процесс сервера вызывает функцию readline, возвращает ошибку ECONNRESET и выводит следующее сообщение:
readline error: Co
Клиентский сокет не должен проходить через состояние ожидания TIME_WAIT, даже если клиент выполняет активное закрытие.
7.4. Первый клиент вызывает функции setsockopt, bind и co
7.5. Запускаем программу на узле без поддержки многоадресной передачи (MacOS X 10.2.6).
macosx % <b>sock -s 9999 &</b> <i>запускаем первый сервер с универсальным адресом</i>
[1] 29697
macosx % <b>sock -s 172.24.37.78 9999</b> <i>пробуем второй сервер, но без -А</i>
can't bind local address: Address already in use
macosx % <b>sock -s -A 172.24.37.78 9999 &</b> <i>пробуем опять с -A: работает</i>
[2] 29699
macosx % <b>sock -s -A 127.0.0.1 9999 &</b> <i>третий сервер с -A; работает</i>
[3] 29700
macosx % <b>netstat -na | grep 9999</b>
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).