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

• Именованные каналы не имеют портов с явно заданными номерами и различаются по именам. 

В случае сервера именованных каналов получение пригодного для работы дескриптора типа HANDLE требует вызова двух функций (CreateNamedPipe и ConnectNamedPipe), тогда как сервер сокета требует вызова четырех функций (socket, bind, listen и accept).

<p>Сравнение клиентов именованных каналов и сокетов</p>

В случае именованных каналов необходимо последовательно вызывать функции WaitNamedPipe и CreateFile. Если же используются сокеты, этот порядок вызовов обращается, поскольку можно считать, что функция socket создает сокет, а функция connect — блокирует.

Дополнительное отличие состоит в том, что функция connect является функцией клиента сокета, в то время как функция ConnectNamedPipe используется сервером именованного канала.

<p>Пример: функция приема сообщений в случае сокета</p>

Часто оказывается удобным отправлять и получать сообщения в виде единых блоков. Как было показано в главе 11, каналы позволяют это сделать. Однако в случае сокетов требуется создание заголовка, содержащего размер сообщения, за которым следует само сообщение. Для приема таких сообщений предназначена функция ReceiveMessage, которая будет использоваться в примерах. То же самое можно сказать и о функции SendMessage, предназначенной для передачи сообщений.

Обратите внимание, что сообщение принимается в виде двух частей: заголовка и содержимого. Ниже мы предполагаем, что пользовательскому типу MESSAGE соответствует 4-байтовый заголовок. Но даже для 4-байтового заголовка требуются повторные вызовы функции recv, чтобы гарантировать его полное считывание, поскольку функция recv не является атомарной.

Примечание, относящееся к Win64

В качестве типа переменных, используемых для хранения размера сообщения, выбран тип данных фиксированной точности LONG32, которого будет вполне достаточно для размещения значений параметра размера, включаемого в сообщения при взаимодействии с системами, отличными от Windows, и который годится для возможной последующей перекомпиляции программы для ее использования на платформе Win64 (см. главу 16).

DWORD ReceiveMessage (MESSAGE *pMsg, SOCKET sd) {

 /* Сообщение состоит из 4-байтового поля размера сообщения, за которым следует собственно содержимое. */ 

 DWORD Disconnect = 0;

 LONG32 nRemainRecv, nXfer;

 LPBYTE pBuffer;

 /* Считать сообщение. */

 /* Сначала считывается заголовок, а затем содержимое. */

 nRemainRecv = 4; /* Размер поля заголовка. */

 pBuffer = (LPBYTE)pMsg; /* recv может не передать все запрошенные байты. */

 while (nRemainRecv > 0 && !Disconnect) {

  nXfer = recv(sd, pBuffer, nRemainRecv, 0);

  Disconnect = (nXfer == 0);

  nRemainRecv –=nXfer;

  pBuffer += nXfer;

 }

 /* Считать содержимое сообщения. */

 nRemainRecv = pMsg->RqLen;

 while (nRemainRecv > 0 && !Disconnect) {

  nXfer = recv(sd, pBuffer, nRemainRecv, 0);

  Disconnect = (nXfer == 0);

  nRemainRecv –=nXfer;

  pBuffer += nXfer;

 }

 return Disconnect;

}

<p>Пример: клиент на основе сокета</p>

Программа 12.1 представляет собой переработанный вариант клиентской программы clientNP (программа 11.2), которая использовалась в случае именованных каналов. Преобразование программы осуществляется самым непосредственным образом и требует лишь некоторых пояснений.

• Вместо обнаружения сервера с помощью почтовых ящиков пользователь вводит IP-адрес сервера в командной строке. Если IP-адрес не указан, используется заданный по умолчанию адрес 127.0.0.1, соответствующий локальной системе.

• Для отправки и приема сообщений применяются функции, например, ReceiveMessage, которые здесь не представлены.

• Номер порта, SERVER_PORT, определен в заголовочном файле ClntSrvr.h.

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