UNIX: разработка сетевых приложений
Часть 299 из 399 Информация о книге
11 while ((с = getopt(argc, argv, "gG")) != -1) {12 switch (c) {13 case 'g': /* свободный маршрут от отправителя */14 if (ptr)15 err_quit("can't use both -g and -G");16 ptr = inet_srcrt_init(0);17 break;18 case 'G': /* жесткий маршрут от отправителя */19 if (ptr)20 err_qint("can't use both -g and -G");21 ptr = inet_srcrt_init(1);22 break;23 case '?':24 err_quit("unrecognized option: %c", c);25 }26 }27 if (ptr)28 while (optind < argc-1)29 len = inet_srcrt_add(argv[optind++]);30 else if (optind < argc-1)31 err_quit("need -g or -G to specify route");32 if (optind != argc-1)33 err_quit("missing <hostname>");34 ai = Host_serv(argv[optind], SERV_PORT_STR, AF_INET, SOCK_STREAM);35 sockfd = Socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);36 if (ptr) {37 len = inet_srcrt_add(argv[optind]); /* получатель в конце */38 Setsockopt(sockfd, IPPROTO_IP, IP_OPTIONS, ptr, len);39 free(ptr);40 }41 Connect(sockfd, ai->ai_addr, ai->ai_addrlen);42 str_cli(stdin, sockfd); /* вызов рабочей функции */43 exit(0);44 }Обработка аргументов командной строкиМы вызываем нашу функцию12-26, чтобы инициализировать маршрут от отправителя. Тип маршрутизации указывается при помощи параметраinet_srcrt_init(свободная) или-g(жесткая).-GЕсли указатель27-33установлен, значит, был указан параметр маршрутизации от отправителя, и все указанные промежуточные узлы добавляются к маршруту, подготовленному на предыдущем этапе функциейptr. Если жеinet_srcrt_addне установлен, но в командной строке еще есть аргументы, значит, пользователь задал маршрут, но не указал его тип. В этом случае программа завершает работу с сообщением об ошибке.ptrОбработка адреса получателя и создание сокетаПоследний аргумент командной строки — это имя узла или адрес сервера в точечно-десятичной записи, который обрабатывается нашей функцией34-35. Мы не можем вызвать функциюhost_serv, так как должны задать маршрут от отправителя между вызовом функцийtcp_connectиsocket. Последняя инициирует трехэтапное рукопожатие, а нам нужно, чтобы сегмент SYN отправителя и все последующие пакеты проходили по одному и тому же маршруту.connectЕсли маршрут от отправителя задан, следует добавить IP-адрес сервера в конец списка адресов (см. рис. 27.1). Функция36-42устанавливает маршрут от отправителя для данного сокета. Затем мы вызываем функцию connect, а потом — нашу функциюsetsockopt(см. листинг 5.4).str_cliНаш TCP-сервер имеет много общего с кодом, показанным в листинге 5.9, но содержит следующие изменения.
Во-первых, мы выделяем место для параметров:
int len;u_char *opts;opts = Malloc(44);Во-вторых, мы получаем параметры IP после вызова функции
, но перед вызовом функцииaccept:forklen = 44;Getsockopt(connfd, IPPROTO_IP, IP_OPTIONS, opts, &len);if (len > 0) {printf("received IP options, len = %d\n", len);inet_srcrt_print(opts, len);}Если сегмент SYN, полученный от клиента, не содержит никаких параметров IP, переменная
по завершении функцииlenбудет иметь нулевое значение (эта переменная относится к типу «значение-результат»). Как уже упоминалось, нам не нужно предпринимать какие-либо шаги для того, чтобы на стороне сервера использовался обращенный маршрут от отправителя: это делается автоматически без нашего участия [128, с. 931]. Вызывая функциюgetsockopt, мы просто получаем копию обращенного маршрута от отправителя. Если мы не хотим, чтобы TCP использовал этот маршрут, то после завершения функции accept следует вызвать функциюgetsockoptи задать нулевую длину (последний аргумент), тем самым удалив все используемые в текущий момент параметры IP. Но маршрут от отправителя тем не менее уже был использован в процессе трехэтапного рукопожатия при пересылке второго сегмента. Если мы уберем параметры маршрутизации, IP составит и будет использовать для пересылки последующих пакетов какой-либо другой маршрут.setsockoptТеперь мы покажем пример клиент-серверного взаимодействия при заданном маршруте от отправителя. Мы запускаем наш клиент на узле
следующим образом:freebsdfreebsd4 % <b>tcpcli01 -g macosx freebsd4 macosx</b>Тем самым дейтаграммы IP отсылаются с узла
на узелfreebsd, обратно на узелmacosx, и наконец, наfreebsd4, где запущен наш сервер. Две промежуточные системыmacosxиfreebsd4должны переправлять дейтаграммы и принимать дейтаграммы с маршрутизацией от отправителя, чтобы этот пример работал.macosx