Циљ ове вежбе је да креирање једноставних клијентских и серверских апликација у којој се демонстрира комуникација путем UDP протокола на одређеном порту. На пример, клијентска апликација треба да шаље текстуалне поруке на задату IP адресу и UDP порт. Серверска апликација треба да прима поруке на задатом UDP порту и приказује их у формату ipadresa_pošiljaoca: primljena poruka
.
UDP клијент
Дизајн форме клијента може бити веома једноставан:
Код клијентске апликације је једноставан и интуитиван. Кликом на дугме иницијализује се стринг ipAdresa
, цео број udpPort
и стринг poruka
. Стринг poruka
конвертује се у низ бајтова dataGram
. Инстанцира се нови објекат udpKlijent
из класе UdpClient
, па се позивају методе Connect
(са параметрима ipAdresa
и udpPort
) и Send (са параметрима dataGram
и дужина низа dataGram
).
using System;
using System.Net.Sockets;
using System.Text;
using System.Windows.Forms;
namespace UDP_klijent
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string ipAdresa = textBox1.Text;
int udpPort = Convert.ToInt32(textBox2.Text);
string poruka = textBox3.Text;
Byte[] dataGram = Encoding.ASCII.GetBytes(poruka);
UdpClient udpKlijent = new UdpClient();
udpKlijent.Connect(ipAdresa, udpPort);
udpKlijent.Send(dataGram, dataGram.Length);
}
}
}
UDP сервер
Дизајн форме UDP сервера може бити још једноставнији:
Израда серверске апликације је мало комплексија, јер док је активан, сервер мора и константно да “слуша” одређени порт. Ако слушање порта имплементирамо у виду бесконачне петље. онда апликација неће моћи да функционише јер се програмске целине извршавају секвенцијално. Ако оставимо простора осталим програмским целинама за фунцкионисање, а слушање порта имплементирамо повремено, онда нисмо направили прави сервер, јер порука од клијента може да стигне баш у тренутку када апликација не слуша порт. Решење је коришћење тредова, тј. нити (енгл. Threads). Тредови омогућавају покретање више програмских целина истовремено.
Идеја је следећа. Удаљени клијент је објекат инстанциран из класе IPEndPoint
из именског простора System.Net
. Да ли сервер јесте или није покренут говори нам глобална променљива stanje
типа bool
. Кликом на button1
, ако је stanje == false
покреће се тред сервера и поставља вредност глобалне промењиве stanje
на true
. Ако је stanje == true
зауставља се тред сервера и поставља вредност глобалне променљиве stanje
на false
. Важно је зауставити активан тред пре искључивања апликације. Тред сервера реализован је као бесконачна петља у којој се примљени низови бајтова конвертују у оригиналне поруке и заједно са адресом пошиљаоца приказују у listBox1
.
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace UDP_Server
{
public partial class Form1 : Form
{
UdpClient udpKlijent = new UdpClient(26300);
IPEndPoint udaljeniKlijent = new IPEndPoint(IPAddress.Any, 2600);
bool stanje = false;
Thread udpServer;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
udpServer = new Thread(new ThreadStart(serverThread));
}
public void serverThread()
{
while (true)
{
Byte[] dataGram = udpKlijent.Receive(ref udaljeniKlijent);
string poruka = Encoding.ASCII.GetString(dataGram);
listBox1.Items.Add(udaljeniKlijent.Address.ToString() + ": " + poruka.ToString());
}
}
private void button1_Click(object sender, EventArgs e)
{
if (stanje == false)
{
udpServer.Start();
listBox1.Items.Add("Server je pokrenut!");
button1.Text = "STOP";
stanje = true;
}
else
{
udpServer.Abort();
listBox1.Items.Add("Server je zaustavljen!");
button1.Text = "START";
stanje = false;
}
}
private void button2_Click(object sender, EventArgs e)
{
if (stanje == true)
MessageBox.Show("Zaustavite server pre zatvaranja aplikacije!");
else
Application.Exit();
}
}
}
Документација
System.Net.Sockets Namespace: https://docs.microsoft.com/en-us/dotnet/api/system.net.sockets
System.Net Namespace: https://docs.microsoft.com/en-us/dotnet/api/system.net
System.Threading Namespace: https://docs.microsoft.com/en-us/dotnet/api/system.threading