Сетевое программирование в .NET, страница 13

В модели Socket-программирования работают с интерфейсами сетевых устройств не прямо, а используют промежуточнные объекты (sockets). Они реализуют функциональность файловых дескрипторов и определяют:

¨  Домен коммуникации, например, сетевое соединение, или Unix IPC (Interprocess Communication) канал,

¨  Тип коммуникации (stream или datagram),

¨  Тип протокола (TCP или UDP).

Как в Unix, так и в Winsock для создания сетевого разъема используется функция:

socket (int domain, int type, int protocol);

Она возвращает целочисленный socket descriptor (типа int в Unix, или типа unsigned int в Windows), но в Windows по традиции для него введен специальный тип данных SOCKET. В Windows первый параметр функции определяет тип разъема (address family) и может принимать 2 значения:

¨  AF_INET — Internet Protocol version 4 (IPv4),

¨  AF_INET6 — Internet Protocol version 6 (IPv6).

В системе Unix этот параметр может принимать одно из 10 возможных значений (Unix IPC, Novell, Amateur radio AX.25, AppleTalk, и т. д.). Нам и далее придется сравнивать Windows-реализацию с реализацией Unix для того, чтобы понять, откуда берется излишняя сложность функций и структур данных. В системе Windows второй параметр функции socket (тип соединения) может принимать 2 значения (в Unix он допускает 5 значений):

¨  SOCK_STREAM — обеспечивает надежное соединение, или двухсторонний механизм передачи последовательного потока байтов, основанный на протоколе TCP.

¨  SOCK_DGRAM — поддерживает механизм datagram, использующий буферы фиксированного размера и основанный на протоколе UDP.

Последний параметр определяет метод (или алгоритм), применяемый для настройки (изменения параметров) протокола связи.

При работе с TCP-разъемом используется значение IPPROTO_TCP. Вообще же этот параметр может принимать множество различных значений, которые зависят от версии Windows. В системах XP/Server 2003 уровню IPPROTO_TCP соответствует настройка (Socket Option) TCP_NODELAY, которая по умолчанию включает Nagle-алгоритм управления задержкой. Он был разработан для борьбы с проблемамаи, создаваемыми пакетами малого размера (tinygrams), которые делают процесс обмена данными неэффективным. В соответствии с Nagle-алгоритмом сетевой разъем копит пакеты в буфере в течение 200 мс, а затем собирает их в один пакет и отправляет. Алгоритм учитывает также и то, что максимальный размер пакета в сети Ethernet составляет 1500 байт.

После того. как разъем (socket) создан, его надо привязать (bind) к паре (сетевой адрес, порт) либо своего, либо удаленного компьютера и только после этого разъем можно использовать для передачи данных.

Понятие address family введено в Unix для того, чтобы в качестве адреса разъема могли использоваться ссылки на различные объекты. Именно это обстоятельство объясняет такой большой размер (14 байт) поля sa_data в структуре sockaddr, которая используется для хранения IP-адреса компьютера, участвующего в обмене по правилам Winsock.

struct sockaddr

{

  unsigned short sa_family;

  char sa_data[14];

};

Совместно с этой структурой (как в Windows, так и в Unix) используется структура sockaddr_in. В ней хранятся пары (сетевой адрес, порт). Последнее поле sin_zero служит для выравнивания размера структуры (так чтобы она могла быть преобразована в структуру sockaddr).

struct sockaddr_in

{

  short sin_family;         // Address family. Оно должно быть равно AF_INET

  unsigned short sin_port;  // IP port

  struct in_addr sin_addr;  // IP address

  char sin_zero[8];         // Padding to make structure the same size as SOCKADDR

};

С помощью sockaddr_in любой (локальный или удаленный) адрес (а точнее, пара типа endpoint) могут быть зааданы или переданы в какую-либо из функций Windows Sockets. Поле sin_addr в свою очередь является структурой типа in_addr. Она определена следующим образом:

struct in_addr

{

  union

  {

    struct { unsigned char s_b1, s_b2, s_b3, s_b4; } S_un_b;

    struct { unsigned short s_w1, s_w2; } S_un_w;