C# 소켓 프로그래밍-1(서버-클라이언트 통신)
Language/C# 2022. 11. 18. 17:08

C# 소켓 프로그래밍-1(서버-클라이언트 통신)

@Beemo9
목차

현재 진행하고 있는 C#기반 메신저 프로젝트에서 소켓 프로그래밍을 사용할 기회가 생겨 정리하게 되었습니다.

우선 이 프로젝트의 목적은 비동기 소켓통신을 통하여 채팅중계서버를 구현하고,

같은 로컬에 있는 각각의 클라이언트에서 채팅을 주고받을 수 있도록 하는 것에 있습니다.

 

일단 한눈에 예제를 확인할 수 있게 콘솔앱으로 작성하였고, 아래는 서버 측 소스코드입니다.

static void Main(string[] args)
        {
            //서버측의 소켓을 생성, 클라이언트와 통신할 연결방식 및 프로토콜 타입을 선언
            Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //모든 네트워크의 클라이언트의 연결을 받을 수 있게 Any작성
            IPAddress ipaddr = IPAddress.Any;
            //ipendpoint = ip:port
            IPEndPoint ipendp = new IPEndPoint(ipaddr, 3000); 
            //소켓에 ipEndPoint 결합
            server.Bind(ipendp);
            //최대 수신대기할 수 있는 인원수 10명으로 지정
            server.Listen(10);
            Console.WriteLine("Connection wait!");
            //클라이언트를 특정지을 수 있는 소켓객체
            Socket client = server.Accept();
            Console.WriteLine("Client Conn, " + client.ToString() + "IP END POINT : " + client.RemoteEndPoint.ToString());
            //수신된 데이터를 받을 수 있는 바이트 배열 선언
            byte[] buff = new byte[128];
            while (true)
            {
                //클라이언트로부터 수신받은 바이트의 길이
                int numberofreceivebytes = client.Receive(buff);
                Console.WriteLine("Number bytes : " + numberofreceivebytes);
                //수신된 텍스트는 바이트임으로 이를 ASCII코드로 인코딩변환
                string receivetext = Encoding.ASCII.GetString(buff, 0, numberofreceivebytes);
                Console.WriteLine("received Text Data : " + receivetext);
                //바이트배열에 담겨져있는 데이터를 클라이언트 측으로 재송신
                client.Send(buff);
                if(receivetext == "x")
                {
                    break;
                }
                //루프를 돌기 전에 데이터 청소
                Array.Clear(buff, 0, buff.Length);
                numberofreceivebytes = 0;
            }
        }

Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

-> 소켓 클래스를 사용하여 서버측의 소켓을 생성하는 구문으로 해당 소켓을 통하여 클라이언트와 통신이 가능합니다.

 

IPAddress ipaddr = IPAddress.Any;

-> 서버에서 모든 네트워크 인터페이스의 클라이언트 동작을 수신 대기해야 함을 나타내는 IP주소를 제공합니다.

 

server.Listen(10);

-> 여기서부터 서버는 소켓을 수신대기 상태로 변환합니다. 매개변수는 수신대기 할 클라이언트 요청 수를 뜻합니다.

 

Socket client = server.Accept();

-> Listen중에 연결요청이 들어온 클라이언트를 담은 큐에서 첫번째 연결요청을 동기적으로 추출하고 새로운 소켓 연결을 만들고 반환합니다.

 

클라이언트의 요청을 받아들인 후 While 무한루프에 진입하게 됩니다.

 

int numberofreceivebytes = client.Receive(buff);

-> Receive()메서드를 통해 클라이언트로부터 데이터를 받을 수 있으며, 해당 메서드의 반환값은 받은 바이트 수입니다.

client.Send(buff);
-> Send()메서드를 활용해 서버측에서도 클라이언트로 데이터를 보낼 수 있습니다.
 

아래는 클라이언트 측 소스코드입니다.

static void Main(string[] args)
        {
            //소켓 객체 생성 (TCP 소켓)
            Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            //끝점 생성
            var ep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 3000);

            //해당 끝점에 소켓 연결
            sock.Connect(ep);

            string cmd = string.Empty;

            byte[] receiverBuff = new byte[8192];

            Console.WriteLine("Connected... Enter Q to exit");

            // Q 를 누를 때까지 계속 Echo 실행
            while ((cmd = Console.ReadLine()) != "Q")
            {
                byte[] buff = Encoding.UTF8.GetBytes(cmd);

                //서버에 데이터 전송
                sock.Send(buff);

                //서버로부터 온 데이터 수신
                int n = sock.Receive(receiverBuff);

                //바이트로 수신한 데이터를 String으로 인코딩
                string data = Encoding.UTF8.GetString(receiverBuff, 0, n);
                Console.WriteLine(data);
            }

            // (5) 소켓 닫기
            sock.Close();
            sock.Dispose();
        }

sock.Connect(ep);

-> 서버와 달리 클라이언트 측에서는 Connect()를 통해 서버측에 연결요청을 전달하는 메서드가 있습니다. 서버측에서는 이렇게 전달된 연결요청을 Listen()메서드를 통해 수신대기 큐에 저장하게 됩니다.

 

sock.Close(); & sock.Dispose();

-> 서버와 연결된 소켓을 닫고 제거합니다.

 

이후는 서버와 동일하게 무한루프 내에서 바이트데이터를 전송 및 수신하는 과정을 진행합니다.

 

아래는 TCP 소켓통신에서 클라이언트와 서버 사이의 통신하는 전체적인 프로세스를 간략하게 보여줍니다.

Beemo9
@Beemo9
개발 기술 블로그, Dev 포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!
image