Добавить в цитаты Настройки чтения

Страница 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 &amp;</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 &amp;</b> <i>пробуем опять с -A: работает</i>

[2] 29699

macosx % <b>sock -s -A 127.0.0.1 9999 &amp;</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).