HOWTO · Csharp

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

C#을 사용하여 .NET 프레임워크에서 클라이언트-서버 통신을 설정하는 방법을 설명하는 프로그래밍 자습서입니다.

이 페이지의 내용

이 간단한 프로그래밍 자습서에서는 클라이언트-서버 환경에서의 데이터 전송에 대해 설명합니다. 또한 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 파일을 실행합니다.

다음 출력이 수신됩니다.

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