Сетевое программирование в .NET. Расшифровка IP-адреса (IP address specification). Обеспечение надежности доставки пакетов, страница 25

Массив tips (массив советов, выдаваемых сервером) вы можете создать самостоятельно, поэтому начните анализ кода, идущего сразу за его объявлением. Сначала сервер создает генератор случайных чисел, используемый для выбора индекса следующего совета. Затем он создает слушателя сети (объект класса TcpListener), который распознает попытки клиентов образовать с ним соединение. На другом конце соединения могут быть два типа объектов: TcpClient или Socket. Наш TcpListener готов образовать соединение и с тем и с другим.

¨  TcpListener содержит внутри себя сетевой разъем (Socket), именно он и производит всю работу. При желании вы можете добыть ссылку на Socket с помощью  свойства Server, но обычно, в простых сценариях этого не делают. Если для вашего приложения функциональности класса TcpListener недостаточно, то вместо него надо использовать класс Socket, что мы и сделаем в следующем проекте. На стороне клиента (в нашем, простом случае) со слушателем будет работать TcpClient, а не Socket, это—упрощенный вариант реализации сетевого соединения.

¨  Слушатель использует специальный IP-адрес—элемент перечисления: IPAddress.Any (мы могли бы задать localhost). Это означает, что при определении адреса своего конца соединения (local endpoint) он полагается на скрытый внутри него service provider.

¨  Метод Start запускает цикл прослушивания сети. Теперь каждый пришедший в порт запрос на соединение слушатель помещает в специальную очередь до тех пор, пока не будет вызван метод Stop (или число запросов в очереди не превысит MaxConnections). Заметьте, что запросы могут сыпаться градом и сервер может не успевать обрабатывать их в режиме реального времени, поэтому он использует очередь. Аналогом методу Start в технологии Winsock являются две API-функции: bind и listen. Мы их использовали ранее.

¨  Метод AcceptSocket (или AcceptTcpClient, так как на сервере вместо Socket'а тоже можно использовать другой класс—TcpClient) выбирает соединение из очереди запросов и обрабатывают его. Если очередь запросов пуста, то AcceptSocket замораживает приложение.

Режим замораживания (ожидания) обозначают термином blocking mode (режим блокировки). Сервер ничего не может делать, пока не придет запрос на обслуживание от какого-либо клиента. Заметьте, что метод recv в приложении Winsock делал то же самое. Во избежание блокировки MSDN предлагает использовать такой алгоритм.

listener.Start();

if (listener.Pending()) // Если очередь не пуста, обслуживаем клиентов

{

socket = listener.AcceptSocket();

. . .// и  т. д.

}

else

{

// Делаем что-то другое

}

Наш сервер не собирается делать ничего другого, он полностью зациклен в выполнении метода AcceptSocket и ждет поступления запросов от клиентов по порту 27015 (вспомните, что говорилось ранее по поводу выбора номера порта). Как только придет запрос от клиента, выполнение серверного приложения возобновляется и оно:

¨  Выводит в свое консольное окно информацию об обслуживаемом клиенте,

¨  Подготавливает очередной совет дня (выбирает его из массива с помощью генератора случайных чисел),

¨  Посылает его текущему клиенту (см. код: socket.Send),

¨  Бесконечный цикл работы сервера продолжается (все серверы работают долго, пока их не выключат).

Вы можете добавить некоторые (показанные ниже) настройки сетевого разъема. Их смысл смотрите в справке.

socket.LingerState = new LingerOption (true, 10);

socket.NoDelay = true;

socket.SendTimeout = 1000;

socket.Ttl = 42;

Разработка клиентского приложения

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