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

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

public static void Main()

{

  try

  {

    IPHostEntry host = Dns.GetHostEntry (Dns.GetHostName());//"localhost"

    foreach (IPAddress address in host.AddressList)

    {

      IPEndPoint point = new IPEndPoint (address, 80);

      Socket socket=new Socket(point.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

      socket.Connect(point);

      if (socket.Connected)

      {

        Console.WriteLine("\n  End Point Info\n" +

          "\n{0,-20}: {1}\n{2,-20}: {3}\n{4,-20}: {5}\n{6,-20}: {7}\n",

          "End Point", point.ToString(),

          "Address", point.Address,

          "AddressFamily", point.AddressFamily,

          "Port", point.Port);

        Console.WriteLine("\n  Socket Info\n" +

          "\n{0,-20}: {1}\n{2,-20}: {3}\n{4,-20}: {5}\n{6,-20}: {7}" +

          "\n{8,-20}: {9}\n{10,-20}: {11}\n{12,-20}: {13}\n{14,-20}: {15}" +

          "\n{16,-20}: {17}\n{18,-20}: {19}\n",

          "SocketType", socket.SocketType,

          "Protocol Type", socket.ProtocolType,

          "Local EndPoint", socket.LocalEndPoint,

          "Remote EndPoint", socket.RemoteEndPoint,

          "Socket Handle", socket.Handle,

          "Is in Blocking Mode", socket.Blocking,

          "Send Timeout", socket.SendTimeout,

          "Receive Timeout", socket.ReceiveTimeout,

          "Send BufferSize", socket.SendBufferSize,

          "Receive BufferSize", socket.ReceiveBufferSize);

        SocketAddress socketAddress = point.Serialize();

        Console.WriteLine("\n  Serialized endpoint\n" +

          "\n{0,-20}: {1}\n{2,-20}: {3}\n{4,-20}: {5}\n",

          "String", socketAddress.ToString(),

          "First byte", socketAddress[0],

          "Family", socketAddress.Family,

          "Size", socketAddress.Size);

        Console.WriteLine("\n  SocketAddress Bytes\n");

        for (int i = 0; i < socketAddress.Size; i++)

          Console.Write("{0}, ", socketAddress[i]);

      }

      socket.Close();

    }

  }

  catch (SocketException e)

  {

    Console.WriteLine("Source: {0}\nMessage: {1}", e.Source, e.Message);

  }

  Console.WriteLine("\n\n");

}

Запустите пример на выполнение проанализируйте его вывод, а затем замените IP-адрес испытуемого узла. Вместо сетевого имени компьютера (Dns.GetHostName()) вставьте имя заглушки ("localhost") и сравните результаты. Убедитесь. что кроме IP-адреса, изменяется номер порта, хранящийся в свойстве LocalEndPoint.

Пояснения. Ссылка на SocketAddress добывается с помощью метода Serialize класса IPEndPoint. Строковое представление (ToString()) объекта SocketAddress производит вывод, логика которого становится ясной только после того, как выведен имеющийся в этом классе специальный буфер.

Класс SocketAddress имеет индексатор, который дает доступ к отдельным байтам своего буфера. Мы используем его для выбора первого байта (AddressFamily) и видим, что он равен константе AF_INET, которую мы использовали ранее в приложении WinSockClient. Ниже выведен весь буфер и мы видим, что его первые 2 байта содержат AddressFamily (они выведены выше в виде строки InterNetwork), третий и четвертый байты хранят номер порта, далее следует IP-адрес. Число 16 в строковом представлении означают размер буфера.

Клиент и сервер