Читаем Системное программирование в среде Windows полностью

В нижеследующем обсуждении под сервером будет пониматься процесс, который принимает запросы на образование соединения через заданный порт. Несмотря на то что сокеты, подобно именованным каналам, могут использоваться для создания соединений между равноправными узлами сети, введение указанного различия между узлами является весьма удобным и отражает различия в способах, используемых обеими системами для соединения друг с другом.

Если не оговорено иное, типом сокетов в наших примерах всегда будет SOCK_STREAM. Сокеты типа SOCK_DGRAM рассматривается далее в этой главе.

<p>Связывание сокета</p>

Следующий шаг заключается в привязке сокета к его адресу и конечной точке (endpoint) (направление канала связи от приложения к службе). Вызов socket, за которым следует вызов bind, аналогичен созданию именованного канала. Однако не существует имен, используя которые можно было бы различать сокеты данного компьютера. Вместо этого в качестве конечной точки службы используется номер порта (port number). Любой заданный сервер может иметь несколько конечных точек. Прототип функции bind приводится ниже. 

int bind(SOCKET s, const struct sockaddr *saddr, int namelen);

Параметры

s — несвязанный сокет, возвращенный функцией socket.

saddr — заполняется перед вызовом и задает протокол и специфическую для протокола информацию, как описано ниже. Кроме всего прочего, в этой структуре содержится номер порта. 

namelen — присвойте значение sizeof (sockaddr).

В случае успешного выполнения функция возвращает значение 0, иначе SOCKET_ERROR. Структура sockaddr определяется следующим образом: 

struct sockaddr {

 u_short sa_family;

 char sa_data[14] ;

};

typedef struct sockaddr SOCKADDR, *PSOCKADDR; 

Первый член этой структуры, sa_family, обозначает протокол. Второй член, sa_data, зависит от протокола. Internet-версией структуры sa_data является структура sockaddr_in: 

struct sockaddr_in {

 short sin_family; /* AF_INET */

 u_short sin_port;

 struct in_addr sin_addr; /* 4-байтовый IP-адрес */

 char sin_zero[8];

};

typedef struct sockaddr_in SOCKADDR_IN, *PSOCKADDR IN; 

Обратите внимание на использование типа данных short integer для номера порта. Кроме того, номер порта и иная информация должны храниться с соблюдением подходящего порядка следования байтов, при котором старший байт помещается в крайней позиции справа (big-endian), чтобы обеспечивалась двоичная совместимость с другими системами. В структуре sin_addr содержится подструктура s_addr, заполняемая уже знакомым нам 4-байтовым IP-адресом, например 127.0.0.1, указывающим систему, чей запрос на образование соединения должен быть принят. Обычно удовлетворяются запросы любых систем, в связи с чем следует использовать значение INADDR_ANY, хотя этот символический параметр должен быть преобразован к корректному формату, как показано в приведенном ниже фрагменте кода.

Для преобразования текстовой строки с IP-адресом к требуемому формату можно использовать функцию inet_addr, поэтому член sin_addr.s_addr переменной sockaddr_in инициализируется следующим образом:

sa.sin_addr.s_addr = inet_addr("192 .13.12.1");

О связанном сокете, для которого определены протокол, номер порта и IP-адрес, иногда говорят как об именованном сокете (named socket). 

<p>Перевод связанного сокета в состояние прослушивания</p>

Функция listen делает сервер доступным для образования соединения с клиентом. Аналогичной функции для именованных каналов не существует. 

int listen(SOCKET s, int nQueueSize); 

Параметр nQueueSize указывает число запросов на соединение, которые вы намерены помещать в очередь сокета. В версии Winsock 2.0 значение этого параметра не имеет ограничения сверху, но в версии 1.1 оно ограничено предельным значением SOMAXCON (равным 5).

<p>Прием клиентских запросов соединения</p>

Наконец, сервер может ожидать соединения с клиентом, используя функцию accept, возвращающую новый подключенный сокет, который будет использоваться в операциях ввода/вывода. Заметьте, что исходный сокет, который теперь находится в состоянии прослушивания (listening state), используется исключительно в качестве параметра функции accept, а не для непосредственного участия в операциях ввода/вывода.

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже