C#에서 UDP 서버 만들기

Saad Aslam 2023년10월12일
C#에서 UDP 서버 만들기

이 기사에서는 C#에서 간단한 UDP 서버를 만드는 방법을 보여줍니다.

C#에서 UDP 서버 생성

간략한 배경 지식을 위해 UDP 프로토콜은 클라이언트와의 연결을 구축할 필요가 없습니다. 클라이언트가 수신했는지 여부를 인증하지 않고 데이터만 전송됩니다.

이 유형의 프로토콜은 일반적으로 데이터를 브로드캐스트하는 데 사용됩니다. UDP는 연결이 없기 때문에 리스너는 메시지를 수신하기 위해 온라인 상태일 필요가 없습니다.

UDP로 데이터그램을 전송하려면 서비스를 호스팅하는 네트워크 장치의 네트워크 주소와 서비스의 UDP 포트 번호를 알아야 합니다. 인기 있는 서비스의 포트 번호는 IANA(Internet Assigned Numbers Authority)에서 정의합니다. 포트 번호의 범위는 1,024~65,535이며 IANA 목록에 없는 서비스에 할당할 수 있습니다.

IP 기반 네트워크에서 특수 네트워크 주소는 UDP 브로드캐스트 메시지를 처리하는 데 사용됩니다. 다음 설명에서는 인터넷의 IP 버전 4 주소 패밀리를 예로 사용합니다.

호스트 식별의 모든 비트를 설정하면 브로드캐스트가 네트워크의 지정된 부분으로 전달될 수 있습니다. 주소 192.168.1.255를 사용하여 IP 주소가 192.168.1로 시작하는 네트워크의 모든 호스트에 브로드캐스트합니다.

이제 소켓을 만들거나 만들고, UDP 프로토콜을 설정하고, 즉시 통신을 시작할 준비가 되었습니다.

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;

이들은 서버 설정에 사용되는 라이브러리입니다. 이러한 라이브러리는 소켓 구축, IPV4 주소 처리 등과 같은 네트워킹과 관련된 모든 기본 기능을 지원합니다.

public class SimpleUdpSrvr {
  public static void Main() {
    int recv;
    byte[] data = new byte[1024];
    IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050);
    Socket newsock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
  }
}

int recv 라인은 클라이언트가 수신한 문자열 메시지의 바이트 수를 포함하는 정수 유형의 recv 변수를 생성합니다.

byte[] data = new byte[byte]; 행은 1024개의 셀(배열 크기라고도 함)을 가진 각 셀에 대해 바이트 크기의 ‘data’라는 배열을 만드는 데 사용됩니다. 이 어레이는 힙에 동적으로 생성됩니다.

IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050); 라인은 소켓에 대한 ipep 변수를 생성하도록 지시합니다. 전달되는 정보는 어떤 종류의 소켓을 사용해야 하는지 알려줍니다.

IPEndPoint 클래스는 IP 주소와 포트 번호가 있는 네트워크 끝점을 나타냅니다. 클라이언트는 서비스에 연결하기 위해 이 구성 정보가 필요합니다. 전달되는 IPAddress.Any 인수는 서버가 9050 포트 번호에 대한 모든 IP 주소로 연결할 수 있음을 알려줍니다. ipep 변수도 동적으로 생성됩니다.

Socket newsock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

이 라인은 우리가 통신할 소켓인 newsock 변수를 생성합니다. 전달되는 인수는 우리가 만들고자 하는 소켓의 종류를 알려줍니다.

AddressFamily.InterNetwork는 로컬 IP 주소를 원한다고 알려줍니다. SocketType.Dgram 인수는 데이터가 패킷 대신 데이터그램으로 흘러야 함을 나타냅니다.

마지막으로 ProtocolType.Udp 인수는 사용할 소켓의 프로토콜 유형을 알려줍니다. 이제 소켓이 생성되었습니다.

newsock.Bind(ipep);
Console.WriteLine("Waiting for a client...");

IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
EndPoint Remote = (EndPoint)(sender);

지금까지 네트워크에 하나의 엔드포인트와 통신할 소켓인 newsock.Bind(ipep);를 만들었습니다. line은 이제 엔드포인트를 소켓에 바인딩하는 데 도움이 됩니다.

ipep은 엔드포인트에 대한 정보를 담고 있는 변수로 newsock 객체의 bind() 함수에 전달됩니다.

Console.WriteLine("Waiting for a client...");

이 줄은 서버가 클라이언트가 메시지를 보내기를 기다리고 있다는 화면에 인쇄합니다. 서버와 통신을 시도할 발신자를 위한 다른 끝점을 만들어야 합니다.

IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);

이 줄은 다른 끝점을 만들고 변수는 sender라고 합니다. IPAddress.Any에 전달된 인수는 우리가 모든 IP 주소를 예상하고 있음을 나타내고 0은 포트 번호에 대한 와일드 카드이며 시스템이 이를 보고 할당한 적절한 포트를 찾아야 함을 의미합니다.

EndPoint 원격 = (EndPoint)(발신자); line은 보낸 사람의 IP 주소를 찾아 remote 변수에 저장하는 데 사용됩니다.

recv = newsock.ReceiveFrom(data, ref Remote);

Console.WriteLine("Message received from {0}:", Remote.ToString());
Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));

프로그램 시작 시 만든 recv 변수는 이제 recv = newsock.ReceiveFrom(data, ref Remote);에서 사용됩니다. 선. 우리는 이전에 생성한 소켓인 newsockReceive() 함수를 사용하고 현재 해당 소켓에 있는 모든 데이터를 수신합니다.

Receive() 함수를 전달하는 인수는 데이터를 저장할 위치와 누구의 데이터가 저장되어야 하는지 또는 예상되는지를 알려줍니다. data 인수는 전달되는 바이트 크기 배열이며 데이터는 데이터 배열로 작성됩니다.

ref Remote 인수는 IP 주소가 데이터를 전송했음을 나타내며 함수는 해당 소켓에서 가져온 바이트 수를 반환하고 recv 변수에 저장합니다.

Console.WriteLine("Message received from {0}:", Remote.ToString());

이 줄은 소켓을 통해 데이터를 보낸 클라이언트의 IP 주소를 화면에 씁니다. 전달된 인수 Remote.ToString()은 10진수를 ASCII 문자로 변환하고 remote 변수는 클라이언트를 참조하는 두 번째 끝점이었습니다.

Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));

이 줄은 화면에 실제 데이터를 씁니다. 소켓을 통해 전송되는 데이터는 원시 형식이며 읽을 수 있도록 ASCII 문자로 변환해야 합니다.

Encoding.ASCII.GetString(data, 0, recv) 라인은 인수로 전달된 data 변수에서 데이터를 가져오고 recv 인수(클라이언트가 보낸 바이트 수 포함)는 다음을 알려줍니다. 화면의 data 변수에서 이 많은 바이트를 씁니다.

string welcome = "Welcome to my test server";
data = Encoding.ASCII.GetBytes(welcome);
newsock.SendTo(data, data.Length, SocketFlags.None, Remote);

string welcome = "Welcome to my test server"; 라인은 Welcome to my test server 텍스트로 welcome 문자열 변수를 초기화합니다.

데이터 = Encoding.ASCII.GetBytes(환영); 라인은 Encoding.ASCII.GetBytes() 함수의 인수로 welcome 변수를 취하고 이를 원시 형식으로 변환하므로 다른 쪽 끝에 있는 소켓을 통해 보낼 준비가 됩니다.

newsock.SendTo(data, data.Length, SocketFlags.None, Remote);

이 줄은 이전에 만든 소켓 newsock을 통해 데이터를 보내고 Send() 함수를 사용합니다. 필요한 인수는 보낼 데이터의 원시 형식을 포함하는 data 변수, 데이터 길이가 바이트 수와 같기 때문에 소켓에 ​​쓸 바이트 수를 나타내는 data.Length 인수입니다. , SocketFlags.None 인수는 모든 플래그를 0으로 유지하고 플래그는 표시기이며 모든 플래그에는 의미가 있습니다.

Remote 변수 인수는 Remote 변수가 클라이언트의 IP 주소와 포트 번호를 저장하므로 데이터를 보내려는 클라이언트에 대해 알려줍니다.

while (true) {
  data = new byte[1024];
  recv = newsock.ReceiveFrom(data, ref Remote);

  Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));
  newsock.SendTo(data, recv, SocketFlags.None, Remote);
}

while(true) 행은 이것이 무한 루프이고 모든 명령문이 무한히 실행될 것임을 알려줍니다. data = new byte[byte]; 행은 실행될 때마다 길이 1024의 새로운 바이트 크기 배열을 만듭니다.

recv = newsock.ReceiveFrom(데이터, 원격 참조); 행은 클라이언트로부터 데이터를 받아 데이터 배열에 저장합니다.

Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv)); 화면에 데이터를 씁니다.

newsock.SendTo(data, recv, SocketFlags.None, Remote); 라인은 서버가 클라이언트로부터 수신한 동일한 데이터를 클라이언트로 다시 보냅니다.

그 후, 서버는 다시 중지하고 클라이언트를 기다리며 클라이언트가 서버에 보내는 모든 메시지는 동일한 메시지로 응답합니다. 이 서버는 충돌하거나 사용자가 수동으로 중지하지 않는 한 절대 종료되지 않습니다.

이제 C#에서 UDP 서버를 만드는 방법과 기본 기능을 배웠으므로 더 많은 기능을 추가하고 요구 사항에 따라 서버를 만들 수 있습니다.

완전한 소스 코드:

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;

public class SimpleUdpSrvr {
  public static void Main() {
    int recv;
    byte[] data = new byte[1024];
    IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050);

    Socket newsock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

    newsock.Bind(ipep);
    Console.WriteLine("Waiting for a client...");

    IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
    EndPoint Remote = (EndPoint)(sender);

    recv = newsock.ReceiveFrom(data, ref Remote);

    Console.WriteLine("Message received from {0}:", Remote.ToString());
    Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));

    string welcome = "Welcome to my test server";
    data = Encoding.ASCII.GetBytes(welcome);
    newsock.SendTo(data, data.Length, SocketFlags.None, Remote);
    while (true) {
      data = new byte[1024];
      recv = newsock.ReceiveFrom(data, ref Remote);

      Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));
      newsock.SendTo(data, recv, SocketFlags.None, Remote);
    }
  }
}
작가: Saad Aslam
Saad Aslam avatar Saad Aslam avatar

I'm a Flutter application developer with 1 year of professional experience in the field. I've created applications for both, android and iOS using AWS and Firebase, as the backend. I've written articles relating to the theoretical and problem-solving aspects of C, C++, and C#. I'm currently enrolled in an undergraduate program for Information Technology.

LinkedIn

관련 문장 - Csharp Server