C#에서 클라이언트-서버 통신 설정

Muhammad Husnain 2024년2월15일
  1. 전송 제어 프로토콜(TCP)
  2. C#에서 클라이언트-서버 통신 설정
C#에서 클라이언트-서버 통신 설정

이 간단한 프로그래밍 자습서에서는 클라이언트-서버 환경에서의 데이터 전송에 대해 설명합니다. 또한 TCP 소켓 프로그래밍을 통해 클라이언트-서버 통신 모델에 C# 기반 구현을 제공합니다.

전송 제어 프로토콜(TCP)

OSI(Open Systems Interconnection)는 컴퓨터가 서로 통신할 수 있는 방법을 설명하는 널리 채택된 통신 참조 모델입니다. 오류 없는 데이터가 한쪽 끝에서 다른 쪽 끝으로 전달되도록 합니다.

계층화된 OSI 모델은 데이터를 보내거나 받을 때 따라야 할 몇 가지 규칙과 프로토콜을 정의합니다. 모든 계층은 개별적으로 작동하며 한쪽 끝에서 다른 쪽 끝으로 데이터를 전송하는 작업을 수행합니다.

이 문서에서는 전송 계층만 설명합니다. 이 계층에서 사용되는 주요 프로토콜은 전송 제어 프로토콜(TCP)이며 다음과 같은 주요 책임이 있습니다.

  1. 두 종단 사이에 연결을 설정하고 통신이 끝나면 연결을 끊습니다.
  2. 다음 작업으로 구성된 데이터 전송:
    • 데이터의 신뢰성을 보장하고 데이터가 순차적으로 전송되고 오류가 없는지 확인합니다.
    • 오류가 있는 경우 오류를 감지하고 손실된 패킷을 다시 보냅니다.
    • 데이터 패킷의 흐름과 속도를 제어합니다.
  3. 확인 및 플래그 설정.

C#에서 클라이언트-서버 통신 설정

C# 언어를 사용하여 .NET 프레임워크에서 클라이언트/서버 응용 프로그램을 구현하는 방법을 살펴보겠습니다. Visual Studio Enterprise Edition 2019를 사용하여 이 구현을 수행할 것입니다.

클라이언트 측과 서버 측을 위한 두 개의 애플리케이션을 만들 것입니다. 테스트를 위해 이 두 응용 프로그램은 모두 같은 컴퓨터에 있습니다.

먼저 클라이언트 응용 프로그램을 만듭니다. 이를 위해 Visual Studio를 열고 새 프로젝트를 만듭니다.

그런 다음 Console Application 프로젝트 유형을 선택하고 Next를 클릭합니다.

콘솔 애플리케이션 선택

프로젝트 이름을 Client Application으로, 솔루션 이름을 ClientServerApplication으로 입력합니다. 이렇게 하면 클라이언트 측을 위한 새 프로젝트가 생성됩니다.

클라이언트 측 프로젝트 이름 및 솔루션 이름 설정

서버 측 프로그래밍의 경우 동일한 솔루션에서 다른 프로젝트를 만듭니다.

서버 측 프로젝트 이름 및 솔루션 이름 설정

이 프로젝트의 이름은 ServerApplication이며 동일한 솔루션에 있습니다.

프로젝트를 생성한 후 Network Comms Dot Net 패키지 파일을 추가해야 합니다. 이를 위해서는 NuGet 콘솔을 사용하여 설치해야 합니다.

이미지에서 다음과 같이 Tools > NuGet Package Manager > Package Manager Console로 이동합니다.

패키지 파일 추가

위의 이미지에서 강조 표시된 것처럼 창에 패키지 관리자 콘솔이 표시됩니다. 이 콘솔에서 다음 명령을 작성합니다.

PM > Install - Package NetworkCommsDotNet - Version 3.0.3

두 프로젝트에 패키지를 성공적으로 설치한 후 코딩을 시작할 수 있습니다. ServerApplication 프로젝트를 열고 코드를 작성합니다.

public static void ConnectServer() {
  IPHostEntry myhost = Dns.GetHostEntry("localhost");
  IPAddress ipAddr = myhost.AddressList[0];
  IPEndPoint myEndPoint = new IPEndPoint(ipAddr, 11000);

  try {
    Socket listenerSocket = new Socket(ipAddr.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

    listenerSocket.Bind(myEndPoint);
    listenerSocket.Listen(5);

    Console.WriteLine("Waiting for Client Socket to Coonect...");
    Socket socketHandler = listenerSocket.Accept();

    // data from the client.
    string myData = null;
    byte[] dataBytes = null;

    while (true) {
      dataBytes = new byte[1023];
      int bytesRece = socketHandler.Receive(dataBytes);
      myData += Encoding.ASCII.GetString(dataBytes, 0, bytesRece);

      if (myData.IndexOf("<EOF>") > -1) {
        myData = myData.Remove(myData.Length - 5);
        break;
      }
    }

    Console.WriteLine("Data Received from Client : {0}", myData);

    byte[] msg = Encoding.ASCII.GetBytes("This is the test msg from server");
    socketHandler.Send(msg);
    socketHandler.Shutdown(SocketShutdown.Both);
    socketHandler.Close();
  } catch (Exception e) {
    Console.WriteLine(e.ToString());
  }

  Console.WriteLine("\n Press any key to continue...");
  Console.ReadKey();
}

그런 다음 클라이언트 측에서 다음 코드를 작성합니다.

public static void ConnectClient() {
  byte[] myBytes = new byte[1024];

  try {
    IPHostEntry myhost = Dns.GetHostEntry("localhost");
    IPAddress ipAddr = myhost.AddressList[0];
    IPEndPoint clientEP = new IPEndPoint(ipAddr, 11000);

    Socket senderSocket = new Socket(ipAddr.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

    try {
      // Connect to the EndPoint
      senderSocket.Connect(clientEP);

      Console.WriteLine("Client Connect to Server at {0}", senderSocket.RemoteEndPoint.ToString());

      // Convert the string into a byte-type array.
      Console.WriteLine("Sending a test message");
      byte[] msg = Encoding.ASCII.GetBytes("This is a test message from Client<EOF>");

      // Send the data using the socket.
      int dataSent = senderSocket.Send(msg);

      // Receive the reply from the server device.
      int dataRec = senderSocket.Receive(myBytes);
      Console.WriteLine("Data Received from Server = {0}",
                        Encoding.ASCII.GetString(myBytes, 0, dataRec));

      // delete the socket
      senderSocket.Shutdown(SocketShutdown.Both);
      senderSocket.Close();
      Console.ReadKey();

    } catch (ArgumentNullException ane) {
      Console.WriteLine(ane.ToString());
    } catch (SocketException se) {
      Console.WriteLine(se.ToString());
    } catch (Exception e) {
      Console.WriteLine(e.ToString());
    }

  } catch (Exception e) {
    Console.WriteLine(e.ToString());
  }
}

해당 프로젝트의 기본 함수에서 이러한 함수를 호출한 후 프로젝트를 빌드해야 하거나 전체 솔루션을 빌드할 수 있습니다. 그런 다음 출력을 실행하려면 이 프로젝트의 파일 탐색기로 이동하여 두 프로젝트의 exe 파일을 실행합니다.

다음 출력이 수신됩니다.

클라이언트-서버 통신 - 출력

Muhammad Husnain avatar Muhammad Husnain avatar

Husnain is a professional Software Engineer and a researcher who loves to learn, build, write, and teach. Having worked various jobs in the IT industry, he especially enjoys finding ways to express complex ideas in simple ways through his content. In his free time, Husnain unwinds by thinking about tech fiction to solve problems around him.

LinkedIn