Skip to content

Једноставнa UDP клијент-сервер апликација

Циљ ове вежбе је да креирање једноставних клијентских и серверских апликација у којој се демонстрира комуникација путем 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