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

Для более близкого знакомства с классом Socket добавьте к существующему решению два новых проекта типа Visual C# Console Application. Один (с именем SocketServer) будет выполнять роль сервера услуг, а второй (с именем SocketClient) будет пользоваться этими услугами.

Услуга сервера состоит в выдаче полезных советов (Tip of the day). Такой сценарий можно использовать в разных ситуациях: выдача текущего прогноза погоды, биржевых котировок акций и т. д. Заметьте, что связь носит односторонний характер. Сервер не интересуется, получил-ли клиент его сообщение, или нет, он не ждет от него подтверждения. Единственной его функцией является реакция на каждое новое соединение и выдача каждому новому клиенту случайно выбранного совета.

class SocketServer

{

public static void Main()

{

  string[] tips =

  {

    "Socket class methods simply marshal data\r\n" +

    "into their native Win32 counterparts.",

    "Socket supports two basic modes\r\n" +

    "synchronous and asynchronous.",

    "In synchronous mode, Send and Receive\r\n" +

    "wait until the operation completes",

    "In asynchronous mode, BeginSend and\r\n" +

    "BeginReceive return immediately.",

    "Applications can use TCP and UDP services with\r\n" +

    "the TcpClient, TcpListener, and UdpClient classes.",

    "Classes: TcpListener, TcpClient and UdpClient\r\n" +

    "use the synchronous methods of the Socket class",

    "TcpListener, TcpClient and UdpClientto provide\r\n" +

    "simple access to network services without\r\n" +

    "the overhead of maintaining state",

  };

  Random r = new Random (DateTime.Now.Millisecond);

  Socket socket = null;

  try

  {

    int port = 27015;

    TcpListener listener = new TcpListener (IPAddress.Any, port); // Listen on port 27015

    listener.Start();

    Console.WriteLine("Waiting for clients to connect to port: {0}\n" +

      "Press Ctrl+c to Quit...", port);

    while (true)

    {

      socket = listener.AcceptSocket(); // Приложение замораживается, если очередь запросов пуста

      IPEndPoint

        local = listener.LocalEndpoint as IPEndPoint,

        remote = socket.RemoteEndPoint as IPEndPoint;

      Console.WriteLine("\nServing client: {0} on port: {1}",

        remote.ToString(), local.Port.ToString());

      int id = r.Next (tips.Length);

      byte[] msg = Encoding.ASCII.GetBytes (tips[id].ToCharArray());

      int bytes = socket.Send (msg, msg.Length, 0);

      Console.WriteLine("\nSent {0} bytes: \n-->{1}", bytes, tips[id]);

    }

  }

  catch (SocketException ex)

  {

    Console.WriteLine((ex.ErrorCode == 10048 ?

      "Another server is listening on this port." : ex.Message));

  }

  finally

  {

    if (socket != null)

    {

      socket.Shutdown (SocketShutdown.Send);

      socket.Close();

    }

  }

}

}

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

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