Для обеспечения сетевых коммуникаций используются сокеты. Сокет это конечная точка сетевых коммуникаций. Каждый использующийся сокет имеет тип и ассоциированный с ним процесс. Сокеты существуют внутри коммуникационных доменов. Домены это абстракции, которые подразумевают конкретную структуру адресации и множество протоколов, которое определяет различные типы сокетов внутри домена. Примерами коммуникационных доменов могут быть: UNIX домен, Internet домен, и т.д.
В Internet домене сокет - это комбинация IP адреса и номера порта, которая однозначно определяет отдельный сетевой процесс во всей глобальной сети Internet. Два сокета, один для хоста-получателя, другой для хоста-отправителя, определяют соединение для протоколов, ориентированных на установление связи, таких, как TCP.
s = socket(domain, type, protocol);
Этот вызов основывается на информации о коммуникационном домене и типе сокета. Для использования особенностей Internet, значения параметров должны быть следующими:
Для создания сокета типа stream с протоколом TCP, обеспечивающим коммуникационную поддержку, вызов функции socket должен быть следующим:
s = socket(AF_INET, SOCK_STREAM, 0);
В Internet домене связывание сокета и имени может быть весьма сложным, но, к счастью, обычно нет необходимости специально привязывать адрес и номер порта к сокету, так как функции connect и send автоматически свяжут данный сокет с подходящим адресом, если это не было сделано до их вызова.
Для связывания сокета с адресом и номером порта используют системный вызов bind:
bind(s, name, namelen);
Привязываемое имя (name) это строка байт переменной длины, которая интерпретируется поддерживаемым протоколом. Интерпретация может различаться в различных коммуникационных доменах.
error = connect(s, serveraddr, serveraddrlen);
которая инициирует установление связи на сокете, используя дескриптор сокета s и информацию из структуры serveraddr, имеющей тип sockaddr_in, которая содержит адрес сервера и номер порта на который надо установить связь. Если сокет не был связан с адресом, connect автоматически вызовет системную функцию bind.
Connect возвращает 0, если вызов прошел успешно. Возвращенная величина -1 указывает на то, что в процессе установления связи произошла некая ошибка. В случае успешного вызова функции процесс может работать с дескриптором сокета, используя функции read и write, и закрывать канал используя функцию close.
Со стороны сервера процесс установления связи сложнее. Когда сервер желает предложить один из своих сервисов, он связывает сокет с общеизвестным адресом, ассоциирующимся с данным сервисом, и пассивно слушает этот сокет. Для этих целей используется системный вызов listen:
error = listen(s, qlength);
где s это дескриптор сокета, а qlength это максимальное количество запросов на установление связи, которые могут стоять в очереди, ожидая обработки сервером; это количество может быть ограничено особенностями системы.
Когда сервер получает запрос от клиента и принимает решение об установлении связи, он создает новый сокет и связывает его с ассоциацией, эквивалентной 'слушающему сокету'. Для Internet домена это означает тот же самый номер порта. Для этой цели используется системный вызов accept:
newsock = accept(s, clientaddr, clientaddrlen);
Сокет, ассоциированный клиентом, и сокет, который был возвращен функцией accept, используются для установления связи между сервером и клиентом.
Процесс установления связи показан на рисунке 1.
Рис. 1: Взаимодействие клиента и сервера
write(s, buf, sizeof(buf)); read(s, buf, sizeof(buf));
Вызовы send и recv практически идентичны read и write, за исключением того, что добавляется аргумент флагов.
send(s, buf, sizeof(buf), flags); recv(s, buf, sizeof(buf), flags);
Могут быть указаны один или более флагов с помощью ненулевых значений, таких, как следующие:
Если сокет больше не используется, процесс может закрыть его с помощью функции close, вызвав ее с соответствующим дескриптором сокета:
close(s);
Если данные были ассоциированы с сокетом, обещающим доставку (сокет типа stream), система будет пытаться осуществить передачу этих данных. Тем не менее, по истечении довольно таки длительного промежутка времени, если данные все еще не доставлены, они будут отброшены. Если пользовательский процесс желает прекратить любую передачу данных, он может сделать это с помощью вызова shutdown на данном сокете для его закрытия. Вызов shutdown вызывает "моментальное" отбрасывание всех стоящих в очереди данных. Формат вызова следующий:
shutdown(s, how);
где how имеет одно из следующих значений: