
1.3 Udp
Як вже було вказано, протокол UDP не вимагає зєднання – данні можуть бути надіслані не одному, а множині отримувачів використовуючи при цьому один сокет.
Для огранизації взаємодії використовується класс System.Net.Sockets.UdpClient в конструктор якого передається адреса віддаленого хоста та номер порту у разі клієнтського додатку, або номер порта в разі серверного.
UdpClient udpc = new UdpClient(2055);
Та
string hostName = Dns.GetHostName();
IPAddress[] ipHostAddressList = Dns.Resolve(hostName).AddressList;
IPAddress ipServerAddress = ipHostAddressList[0];
UdpClient udpc = new UdpClient(ipServerAddress.ToString(), 2055);
Отримання даних здійснюється з використанням методу Receive:
IPEndPoint ep = null;
byte[] data = udpc.Receive(ref ep);
де
data – байтовий масив, в який зберігаються отримані дані
ep – адреса відправника.
Відправка даних здійснюється з використанням методу Send.
Якщо адреса віддаленого хоста була задана в конструкторі використовується
виклик методу
udpc.Send(sdata, sdata.Length);
де
data – байтовий масив
Інакше, в метод передається адреса процесу отримувача
udpc.Send(sdata, sdata.Length, ep);
де
IPEndPoint ep – адреса отричувача.
Розглянемо задачу віддаленої ідентифікації користувача.
Серверна програма має вигляд.
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace SocketTest
{
public class UDPServer
{
public void Run()
{
UdpClient udpc = new UdpClient(2055);
Console.WriteLine("Server started on port 2055");
IPEndPoint ep = null;
string PID;
string status = "not identified";
while (true)
{
byte[] rdata = udpc.Receive(ref ep);
PID = Encoding.ASCII.GetString(rdata);
//Some logic to identify
if (PID == "12345")
status = "identified";
byte[] sdata = Encoding.ASCII.GetBytes(status);
udpc.Send(sdata, sdata.Length, ep);
}
}
}
}
Клієнтська програма.
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace SocketTest
{
public class UDPClient
{
public void Run()
{
string hostName = Dns.GetHostName();
IPAddress[] ipHostAddressList = Dns.Resolve(hostName).AddressList;
IPAddress ipServerAddress = ipHostAddressList[0];
UdpClient udpc = new UdpClient(ipServerAddress.ToString(), 2055);
IPEndPoint ep = null;
while (true)
{
Console.Write("Enter your personal identifier: ");
string PID = Console.ReadLine();
if (PID == "" )
{
//Console.Write("Press ESC to quit. ");
break;
}
//
byte[] sdata = Encoding.ASCII.GetBytes(PID);
udpc.Send(sdata, sdata.Length);
byte[] rdata = udpc.Receive(ref ep);
string status = Encoding.ASCII.GetString(rdata);
Console.WriteLine(status);
if (status == "identified")
{
break;
}
}
}
}
}
Тестова програма має вигляд.
private static UDPServer udpserver = new UDPServer();
private static UDPClient udpclient = new UDPClient();
static void Main(string[] args)
{
Thread serverThread = new Thread(startUDPServer);
serverThread.IsBackground = true;
serverThread.Start();
Console.WriteLine("Press ENTER to test interaction...");
if (Console.ReadKey().Key == ConsoleKey.Enter) ;
{
udpclient.Run();
}
}
private static void startUDPServer()
{
udpserver.Run();
}
Результати тесту показан на рис.
Рис.
Розглянемо приклад посилки однієї датаграми декільком отримувачам. Для цього отправувач відправляє пакети на адресу в діапазоні 224.0.0.1 - 239.255.255.255(Class D address group). Отримувачі можуть увійти в цю групу (join the group) та почати отримувати пакети. Вход в групу здійснюється методом JoinMulticastGroup(addr).
Розглянемо приклад публікації цін на товар «product» сервером, що здійснюється кожні 5 секунд. Для цього на адресу 230.0.0.1 відправляється датаграма, яку отримуєть клієнти, що входять у групу.
Код сервера
public class UDPPublisher
{
private string product = "Product";
public void Run()
{
UdpClient publisher = new UdpClient("230.0.0.1",8899);
Console.WriteLine("Publishing stock prices to 230.0.0.1:8899");
Random gen = new Random();
while(true)
{
double price = 400*gen.NextDouble()+100;
string msg = String.Format("{0} {1:#.00}",product,price);
byte[] sdata = Encoding.ASCII.GetBytes(msg);
publisher.Send(sdata,sdata.Length);
System.Threading.Thread.Sleep(5000);
}
}
}
Код клієнта
class UDPSubscriber
{
public void Run()
{
UdpClient subscriber = new UdpClient(8899);
IPAddress addr = IPAddress.Parse("230.0.0.1");
subscriber.JoinMulticastGroup(addr);
IPEndPoint ep = null;
for(int i=0; i<10;i++){
byte[] pdata = subscriber.Receive(ref ep);
string price = Encoding.ASCII.GetString(pdata);
Console.WriteLine(price);
System.Threading.Thread.Sleep(3000);
}
subscriber.DropMulticastGroup(addr);
}
}
Код тестера
private static UDPPublisher udppublisher = new UDPPublisher();
private static UDPSubscriber udpsubscriber = new UDPSubscriber();
static void Main(string[] args)
{
Thread serverThread = new Thread(startUDPPublisher);
serverThread.IsBackground = true;
serverThread.Start();
Console.WriteLine("Press ENTER to test interaction...");
if (Console.ReadKey().Key == ConsoleKey.Enter) ;
{
udpsubscriber.Run();
Console.WriteLine("Press ESC to exit");
while (true)
{
if (Console.ReadKey().Key == ConsoleKey.Escape)
{
break;
}
}
}
}
private static void startUDPPublisher()
{
udppublisher.Run();
}
Результат
Рис.
Завдання
На мінімальний бал:
1.Реалізувати всі приклади, що наведені в лабораторній роботі. Пояснити особливості описаних протоколів, варіантів організації взаємодії за допомогою сокетів.
Іншим:
До наведених варіантів «асинхронних» серверів написати варіанти асинхронних клієнтів.
Здійснити серверну обробку потоку сирих даних (потоку байтів) що поступають від клієнтів зі зберіганням їх в базі даних. Наприклад, існує множина пристроїв, кожен з яких раз в мінуту передає потік посекундних двобайтних значень певних характеристик. Організувати паралельну обробку. Обробити варіанти втрати зв’язку, невиходу в означений термін (здійснення прийому інформації з попередніх сеансів).
Реалізувати версію системи публікації-подписки цін на товари. Декілька серверів публікують свої ціни на товари, клієнти отримують ці ціни, виконують порівняння та виводять в GUI-інтерфейс користувача порівняльну по вказаному товару. Здійснити прийом(зберігання та відображення) цін з інтервалом визначеним користувачем.
Написати простішу програму чат на базі архітектури «клієнт-сервер» з використанням вивчених технологій.