В заголовочном файле unp.h мы используем директиву #define SA, чтобы определить SA как struct sockaddr, что соответствует общей структуре адреса сокета. Каждый раз, когда одна из функций сокетов требует указателя на структуру адреса сокета, этот указатель должен быть преобразован к указателю на общую структуру адреса сокета. Это происходит потому, что функции сокетов появились раньше, чем стандарт ANSI С. Соответственно, тип указателя void* не был доступен в начале 80-х, когда эти функции были разработаны. Проблема состоит в том, что "struct sockaddr" занимает 15 символов и часто заставляет выходить строку исходного кода за правую границу экрана (или за страницу книги), поэтому мы сократили ее до SA. Более подробно мы исследуем общие структуры адресов сокетов на примере листинга 3.2.
19-25
Мы читаем ответ сервера и отображаем результат, используя стандартную функцию ввода-вывода fputs
. Нужно быть внимательным при использовании TCP, поскольку это
Fri Jan 12 14:27:52 1996\r\n
где \r
— это возврат каретки, а \n
— перевод строки (в символах ASCII). В случае потокового протокола эти 26 байт можно получить в нескольких вариантах: в виде отдельного сегмента TCP, содержащего все 26 байт данных, либо в виде 26 сегментов, каждый из которых содержит по одному байту данных, или в виде любой другой комбинации, в сумме дающей 26 байт. Обычно возвращается один сегмент, содержащий все 26 байт, но при больших объемах данных нельзя рассчитывать, что ответ сервера будет получен с помощью одного вызова read
. Следовательно, при чтении из сокета TCP нужно всегда вызывать функцию read
циклически и прерывать цикл либо когда функция возвращает 0 (например, соединение было разорвано другой стороной), либо когда возвращенное значение оказывается меньше нуля (ошибка).
В приведенном примере конец записи обозначается сервером, закрывающим соединение. Эта технология используется также версией 1.0 протокола передачи гипертекста (Hypertext Transfer Protocol, HTTP). Существуют и другие способы обозначения конца записи. Например, протокол передачи файлов (File Transfer Protocol, FTP) и простой протокол передачи почты (Simple Mail Transfer Protocol, SMTP) обозначают конец записи 2-байтовой последовательностью, состоящей из символов ASCII возврата каретки и перевода строки. Служба вызова удаленных процедур (Remote Procedure Call, RPC) и система именования доменов (Domain Name System, DNS) помещают перед каждой записью, отсылаемой по протоколу TCP, двоичное число, соответствующее длине этой записи. Здесь важно осознать, что протокол TCP сам по себе не предоставляет никаких меток записей: если приложение хочет отделять записи одну от другой, оно должно делать это самостоятельно, и для этого имеются стандартные методы.
26
Функция exit
завершает программу. Unix всегда закрывает все открытые дескрипторы при завершении процесса, поэтому теперь наш сокет TCP закрыт.
Как уже говорилось, пока мы лишь выделили наиболее важные моменты, детальным исследованием которых займемся в дальнейшем.
1.3. Независимость от протокола
Наша программа, представленная в листинге 1.1, является sockaddr_in
, определяем адрес как относящийся к семейству AF_INET и устанавливаем первый аргумент функции socket
равным AF_INET
.
Если мы хотим изменить программу так, чтобы она работала по протоколу IPv6, мы должны изменить код. В листинге 1.2 показана новая версия программы с соответствующими изменениями, отмеченными полужирным шрифтом.
Листинг 1.2. Версия листинга 1.1 для IPv6
//intro/daytimetcpcliv6.с
1 #include "unp.h"
2 int
3 main(int argc, char **argv)
4 {
5 int sockfd, n;
6 char recvline[MAXLINE + 1];
Вильям Л Саймон , Вильям Саймон , Наталья Владимировна Макеева , Нора Робертс , Юрий Викторович Щербатых
Зарубежная компьютерная, околокомпьютерная литература / ОС и Сети, интернет / Короткие любовные романы / Психология / Прочая справочная литература / Образование и наука / Книги по IT / Словари и Энциклопедии