Programming/.NET

UDP는 간단하게 서버와 클라이언트가 데이터를 송수신할 수 있지만 일단 데이터를 보내면 상대측이 잘 받았는지 확인할 도리가 없고 심지어 여러건의 데이터를 나누어 보내면 순서대로 받을 수 있을지 조차 장담할 수 없습니다. 따라서 신뢰성이 너무 약해 잘 쓰지 않는 통신방식입니다.

 

지금은 간단하게 C#으로 UDP통신이 가능한 서버와 클라이언트 프로그램을 구현해 보고자 합니다. 통신 방식은 클라이언트가 서버에 특정 데이터를 보내면 서버는 이 데이터를 받아 앞에 'server : ' 라는 문자열을 추가한뒤 다시 클라이언트에 보내는 방식입니다.

 

static void Main(string[] args)
{
    Thread t = new Thread(myMethod);
    t.IsBackground = true;

t.Start();

Console.Read();

}

 

static void myMethod(object o)
{
    using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)) {
        IPEndPoint iEp = new IPEndPoint(IPAddress.Any, 2020);
        socket.Bind(iEp);

        byte[] bRec = new byte[1024];
        EndPoint ep = new IPEndPoint(IPAddress.None, 0);

        while (true) {
            int i = socket.ReceiveFrom(bRec, ref ep);
            string s = Encoding.UTF8.GetString(bRec, 0, i);

            byte[] bSnd = Encoding.UTF8.GetBytes("server : " + s);
            socket.SendTo(bSnd, ep);
        }
    }
}

 

우선 서버측부터 구현해 보겠습니다. 제일 먼저 필요한건 소켓입니다. Socket클래스를 통해 socket을 생성하는데 ProtocolType을 Udp로 지정해 UDP로 통신할 것임을 알려줍니다.

 

서버는 경우에 따라 다수의 IP를 가질 수 있습니다. 이 가운데 지금 통신을 위해 어떤 IP와 포트로 수신대기를 해야하는지를 정해야 하며 그 접점을 IPEndPoint클래스로 설정합니다. IPAddress.Any는 현재 시스템에 마련된 모든 IP를 대상으로 하겠다는 것을 의미하며 2020은 포트번호에 해당합니다. 만약 특정 IP를 명시적으로 지정하고자 한다면 다음과 같이 코드를 수정할 수 있습니다.

 

IPAddress ip = IPAddress.Parse("192.168.20.126");
IPEndPoint iEp = new IPEndPoint(ip, 2020);

 

접점이 마련되었으면 socket의 Bind 메서드를 통해 해당 접점정보를 전달하여 설정된 네트워크정보로 데이터를 수신대기하도록 합니다.

 

bRec는 클라이언트로 부터 데이터가 수신되면 받을 버퍼이며 ep는 클라이언트측 접점정보를 가진 개체입니다. 그런데 어떤 클라이언트로 부터 데이터가 수신될지 모르니 IPEndPoint로 인스턴스를 생성할때는 IP를 지정하지 않고 또한 포트도 0으로 설정할 수 밖에 없습니다. 특정 내용으로 설정한다 하더라도 이개체는 socket의 ReceiveFrom메서드에서 데이터가 수신될때 데이터를 보낸 접점정보를 담아 반환하게될 것이므로 초기설정정보는 그렇게 의미가 없습니다.

 

ReceiveFrom메서드에서 데이터가 수신되면 bRec버퍼에 수신된 내용을 담은 후 UTF8인코딩을 통해 문자열로 변환한 후 앞단에 'sever : '라는 내용을 붙여 SendTo메서드를 통해 받은 데이터를 다시 보냅니다. 이때 어느 클라이언트로 보낼지는 ep개체를 통해 알 수 있습니다. ep는 초기화 시에는 의미없는 내용이었지만 ReceiveForm에서 정보가 담겨지게 되므로 클라이언트의 접점정보를 알 수 있게 됩니다.

 

또한 SendTo로 데이터를 보낼때는 보낼 수 있는 데이터의 크기도 생각을 해봐야 합니다. 이론상으로는 최대 65535byte인데 이는 네트워크통신에서 패킷에 붙는 별도의 정보로 인해 크기가 줄어들 수 있을 뿐만 아니라 각종 네트워크장비에서 통과할 수 있는 데이터의 양을 제한하는 경우도 있으므로 주의해야 합니다.

 

static void Main(string[] args)
{
    Thread t = new Thread(myMethod);
    t.IsBackground = true;


    t.Start();

    Console.Read();
}

static void myMethod(object o)
{
    Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

    IPAddress ip = IPAddress.Parse("192.168.20.126");
    EndPoint sEP = new IPEndPoint(ip, 2020);

    EndPoint cEP = new IPEndPoint(IPAddress.None, 0);

    byte[] send = Encoding.UTF8.GetBytes("hi server!!");
    socket.SendTo(send, sEP);

    byte[] rec = new byte[1024];
    int i = socket.ReceiveFrom(rec, ref cEP);
    string s = Encoding.UTF8.GetString(rec, 0, i);

    Console.WriteLine(s);

    socket.Close();
}

 

위 예제는 클라이언트측 예제로서 소켓생성방법은 서버와 같습니다.

 

클라이언트입장에서 데이터를 보낼때 어느 서버로 보낼지를 알아야 하므로 그에 대한 설정을 진행합니다. 서버의 IP는 192.168.20.126(여러분의 환경에 따라 IP는 다를 것입니다!)이며 포트 2020으로 접속할 것입니다. 또한 서버에 데이터를 보낸 후 다시 서버에서 메세지를 수신받아야 하는데 이때 필요한 접점정보도 필요합니다. 다만 이미 서버정보에 대해서는 알고 있으나 어차피 ReceiveFrom에서 데이터를 보낸 대상의 접점정보가 파악될 것이므로 굳이 IP와 포트정보를 따로 지정하지 않습니다.

 

데이터를 보낼때는 보낼 내용을 UTF8로 인코딩하여 바이트배열에 담아 SendTo메서드에 전달해 데이터를 송신합니다. 이때 서버측 접점정보도 매개변수를 통해 같이 전달합니다.

 

서버에 데이터를 송신하면 그 즉시 서버에서 특정 메세지가 회신될 것이므로 그 회신데이터를 담을 버퍼를 마련해 두고 ReceiveFrom 메서드에 전달합니다. 그리고 버퍼에 담긴 내용을 다시 UTF8로 디코딩하여 사용자에게 보내줍니다.

 

UDP통신은 앞서 말한대로 데이터를 송수신할때의 신뢰성이 떨어지지만 데이터를 보내면 데이터를 받는 쪽에서는 보낸만큼 한꺼번에 데이터를 수신받을 수 있는등 통신방식은 대단히 간결하다는 장점이 있습니다.

'Programming > .NET' 카테고리의 다른 글

[C#] 네트워크 - TCP  (0) 2018.10.17
[ASP.NET MVC] 영역(Area)  (0) 2018.10.10
[C#] 네트워크 - UDP  (0) 2018.09.20
[C#] async / await  (0) 2018.09.04
[C#] Path  (0) 2018.08.23
[ASP.NET MVC] 뷰 (View)  (0) 2018.08.14
0 0