C#

소켓 프로그래밍 기초

monstro 2024. 12. 16. 17:14
728x90
반응형

서버 - 클라이언트 프로그래밍에서 소켓 프로그래밍은

서버와 클라이언트 모두 연결을 위한 대리자, 즉 소켓을 이용하여 서로 연결하는 프로그래밍입니다.

이때 서버와 클라이언트의 진행 방식에 있어서 서로 차이점이 존재합니다.

 

1) 클라이언트 단계의 소켓 프로그래밍

클라이언트는 소켓을 준비하여 서버 주소로 Connect를 요청할 수 있습니다.
그리고 Connect 요청이 받아들여진 후 

서버 소켓을 통해 Session 소켓과 패킷을 서로 송신/수신할 수 있습니다.

 

2) 서버 단계의 소켓 프로그래밍

서버는 클라이언트와 다르게 소켓 프로그래밍을 위한 준비 절차가 조금 복잡합니다.

그 절차를 간단하게 다음과 같이 표현할 수 있습니다.

 

  • 클라이언트로부터 접속 요청(=Connect)을 받는 Listener 소켓 준비
  • 준비된 Listener 소켓에 대해 Bind(서버의 주소/Port를 소켓에 연동)
  • 접속 요청(=Connect)을 받기 위해 Listen 상태에 돌입
  •  Listen 상태에서 접속 요청(=Connect)이 들어오면 Accept

 

위와 같은 절차로 서버에서는 소켓 프로그래밍이 동작하게 됩니다.

그리고 서버에서는 클라이언트 소켓을 통해 클라이언트와 Session 소켓과 패킷을 서로 송/수신합니다.

 

그렇다면 이제 실제 코드를 통해 클라이언트-서버간의 소켓 프로그래밍을 구현해보겠습니다.

1) Server 코드

static void Main(string[] args)
{
    // DNS를 사용
    string host = Dns.GetHostName();
    IPHostEntry ipHost = Dns.GetHostEntry(host);
    IPAddress ipAddr = ipHost.AddressList[0];
    IPEndPoint endPoint = new IPEndPoint(ipAddr, 7777);

    // Server의 ClientSocket을 TCP로 동작하게끔 설정
    Socket listenSocket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

    try
    {
        // ClientSocket에 대해 bind
        listenSocket.Bind(endPoint);

        // Listen 상태 설정 - 최대 대기수
        listenSocket.Listen(10);

        while (true)
        {
            Console.WriteLine("Listening...");

            // Client로부터 Connect가 들어오는 경우, ClientSocket으로 Accept함
            Socket ClientSocket = listenSocket.Accept();

            // Client로부터 받은 내용을 기록
            byte[] recvBuffer = new byte[1024];
            int recvBytes = ClientSocket.Receive(recvBuffer);
            string recvData = Encoding.UTF8.GetString(recvBuffer, 0, recvBytes);
            Console.WriteLine($"From Client : {recvData}");

            // Client로 전달
            byte[] sendBuffer = Encoding.UTF8.GetBytes("Welcome to Server!!!");
            ClientSocket.Send(sendBuffer);

            // Client와의 연결 중지 - 우선 Client의 ServerSocket 연결 중지
            ClientSocket.Shutdown(SocketShutdown.Both);
            ClientSocket.Close();

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

 

2) Client 코드

static void Main(string[] args)
{
    // DNS를 사용
    string host = Dns.GetHostName();
    IPHostEntry ipHost = Dns.GetHostEntry(host);
    IPAddress ipAddr = ipHost.AddressList[0];
    IPEndPoint endPoint = new IPEndPoint(ipAddr, 7777);

    // Server Socket 설정
    Socket socket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

    try
    {
        // Server에게 Connect 요청
        socket.Connect(endPoint);
        Console.WriteLine($"Connected to {socket.RemoteEndPoint.ToString()}");

        // 서버로 전송
        byte[] sendBuffer = Encoding.UTF8.GetBytes("Hello From Client");
        int sendBytes = socket.Send(sendBuffer);

        // 서버로부터 받음
        byte[] recvBuffer = new byte[1024];
        int recvBytes = socket.Receive(recvBuffer);
        string recvData = Encoding.UTF8.GetString(recvBuffer, 0, recvBytes);
        Console.WriteLine($"From Server : {recvData}");

        // Server 소켓 종료
        socket.Shutdown(SocketShutdown.Both);
        socket.Close();
    }
    catch (Exception e)
    { 
        Console.WriteLine(e.ToString());
    }
}

 

이제 두 코드를 빌드하여 실제 실행결과를 확인해보겠습니다.

 

문제없이 동작하여

Client는 연결을 수행한 후 종료되었고,

Server는 무한 반복문을 실행하여 동작중인 것을 확인할 수 있습니다.

728x90
반응형

'C#' 카테고리의 다른 글

Session_1  (0) 2024.12.24
Listener  (0) 2024.12.18
네트워크 기초 + 통신 모델  (0) 2024.12.11
Thread Local Storage  (0) 2024.12.09
ReaderWriterLock 구현  (0) 2024.12.09