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

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

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

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

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

Для более близкого знакомства с классом 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();

}

}

}

}