Skip to content

Latest commit

 

History

History
156 lines (135 loc) · 6.16 KB

2.4_소켓_프로그래밍_입문_2.md

File metadata and controls

156 lines (135 loc) · 6.16 KB

ServerCore

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

namespace ServerCore
{
    class Program
    {
        static void Main(string[] args)
        {
            // DNS(Domain Name System)
            // 서버의 주소를 하드 코딩으로 넣는 게 아니라 
            // Domain 이름으로 IP 주소를 받아오는 방법
            // 어떻게 이게 가능한지?
            // 매우 어려운 주제이지만 
            // Dns 서버가 네트워크망 안에 있어서
            // 이걸 해줌
            string host = Dns.GetHostName();
            IPHostEntry ipHost =  Dns.GetHostEntry(host);

            // 하나의 도메인에 여러개의 IP를 관리할 수도 있기 때문에 배열 타입으로 받아온다.
            IPAddress ipAddr = ipHost.AddressList[0];
            
            // 최종 주소
            // ipAddr : 식당 주소에 해당
            // 7777(port) : 식당 정문인지 후문인지 알려 줌
            // 클라이언트가 7777이 아니라 어뚱한 번호로 입장을 하려고 한다면 입장이 불가
            IPEndPoint endPoint = new IPEndPoint(ipAddr, 7777);
            
            // 문지기가 들고 있는 휴대폰
            // endPoint 넣는 위치는 IPv4, IPv6를 사용할지 결정
            // 이미 endPoint를 가져올 때 정해졌기 때문에 AddressFamily로 가져오면 됨
            Socket listenSocket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
            try
            {
                // 문지기 교육
                listenSocket.Bind(endPoint);

                // 영업 시작
                // 최대 대기수
                // 동시 다발로 너무 많은 사람이 
                // 최대 10명까지만 대기가 가능하고
                // 10명 이후에 사람들이 입장이 가능한지 물었을 때
                // 무조건 Fail이 뜨게 만듬
                listenSocket.Listen(10);

                // 입장 대기
                while(true)
                {
                    System.Console.WriteLine("Listening...");

                    // 손님을 입장시킨다.
                    // clientSocket : 대리인
                    // 손님과의 대화는 앞으로 대리인을 통해 진행
                    // 손님이 입장을 안한다면?
                    // 요게 Blocking 함수
                    Socket clientSocket = listenSocket.Accept();

                    // 손님의 메시지를 받는다 
                    byte[] recvBuff = new byte[1024];
                    
                    // 손님의 메시지가 recvBuff에 저장된다.
                    // 몇 바이트인지는 recvByte에 저장된다.
                    int recvByte = clientSocket.Receive(recvBuff);
                    // Encoding : 전달 받은 한글 메시지를 어떻게 변환할 것인지 정하는 것
                    // 0 : 시작 인덱스, 전달 받은 데이터가 어디서부터 있는지
                    // 전달 받은 메시지의 Byte 수
                    string recvData = Encoding.UTF8.GetString(recvBuff, 0, recvByte);
                    System.Console.WriteLine($"[From Client : {recvData}");

                    // 손님에게 메시지를 보낸다.
                    // recvBuff는 얼마나 받을 지 모르기 때문에 크기를 1024로 정했지만
                    // 보낼 때는 얼마나 보낼지 알 수 있기 때문에 바로 여기서 생성한다.
                    byte[] sendBuff = Encoding.UTF8.GetBytes("Welcome to MMORPG Server! ");
                    clientSocket.Send(sendBuff);

                    // 쫓아낸다
                    // 좀더 우아하게 종료가 됨
                    clientSocket.Shutdown(SocketShutdown.Both);
                    clientSocket.Close();
                }
            }
            catch(Exception e)
            {
                System.Console.WriteLine(e.ToString());
            }
        }
        // 주의 사항
        // 게임에서는 Accept, Connect, Receive와 같은 Blocking 계열 함수를 사용해서는 안된다.
        // 만약에 Connect를 했을 때 성공을 못하면 계속 대기를 해야하기 때문에 위험
        // 
    }
}

Dummy Client

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

namespace DummyClient
{
    class Program
    {
        static void Main(string[] args)
        {
            // 식당의 주소를 찾는 과정은 동일함
            string host = Dns.GetHostName();
            IPHostEntry ipHost =  Dns.GetHostEntry(host);
            IPAddress ipAddr = ipHost.AddressList[0];
            IPEndPoint endPoint = new IPEndPoint(ipAddr, 7777);
            
            // 휴대폰 설정
            // ProtocolType.Tcp로 결정을 하면 SocketType도 Stream으로 자동으로 결정이 된다.
            Socket socket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);  
            
            try
            {
                // 문지기한테 입장 문의를 함
                // 상대방의 주소를 넣어줘야함
                // 문지기한테 연락이 닿을 때까지 대기
                socket.Connect(endPoint);

                // 서버의 정보를 출력
                // 연결한 대상의 서버의 정보
                System.Console.WriteLine($"Connected to {socket.RemoteEndPoint.ToString()}");

                // 서버로 보낸다
                byte[] sendBuff = Encoding.UTF8.GetBytes("Hello World!");
                int sendByte = socket.Send(sendBuff);

                // 서버로부터 받는다
                byte[] recvBuff = new byte[1024];
                int recvBytes = socket.Receive(recvBuff);
                string recvData = Encoding.UTF8.GetString(recvBuff, 0, recvBytes);
                System.Console.WriteLine($"[From server] {recvData}");

                // 나간다
                socket.Shutdown(SocketShutdown.Both);
                socket.Close();
            }
            catch (Exception e)
            {
                System.Console.WriteLine(e.ToString());
            }
        }
    }
}