개인공부) 서버실습(19) - 소켓프로그래밍 기초

Justin·2022년 6월 11일
0

서버공부

목록 보기
18/45
post-custom-banner

✅ 지난 시간

TCP/IP 5계층이라는 구분을 통해 네트워크가 어떻게 동작하는지 간단하게 알 수 있었다. 구조마다 각자 하는 일이 다르구나 정도만 이해한 상태라 틈틈히 찾아보고 이해해야겠다.

🔌 소켓 프로그래밍 기초

소켓이란?
네트워크 송수신할 수 있도록 '네트워크 환경에 연결할 수 있게 만들어진 연결부'이다.

오늘도 역시나 레스토랑 스토리로 비유를 해주셨다. 우선 손님과 가게 두가지의 구분이 있고 아래와 같은 순서로 일을 하게 된다.

손님가게
  가게에 가고 싶은 손님   입구 만들기, 문지기 고용 
-문지기 교육
입장 문의영업 시작
(제한적으로 손님받음)
소통(직원)안내(소통)

손님은 자신이 가는 것이 아닌 대리자가 가는 걸 대신 입장 문의하여 식당에 보내는 것이고, 가게는 문지기를 통해 손님의 요청을 받을지 말지 결정하고, 받게 되면 안내하게 되며

서로 소통이 가능한 상태가 된다. 이러한 상황을 소켓 프로그래밍에 대입하면 아래와 같은 구조가 된다.


클라이언트가 손님, 가게가 서버의 역할을 하며 손님은 비교적 간단한 과정으로 소통을 하게 요청할 수 있고

서버에서는 주소, Port를 결합하거나 요청 대기 및 승인 들의 절차가 있기에 비교적 많은 일을 하게 된다.

너무 도움된 자료: https://recipes4dev.tistory.com/153


💡 소켓 프로그래밍 구현

😶 서버 제작

DNS (Domain Name System)
IP 주소를 도메인 주소(www.google.com) 로 변경해주는 것. (서버의 주소가 변경 될 수도 있기에 도메인을 사용하는 게 좋음)

😙 사전 준비

기본으로 Dns 프로토콜을 이용해 세팅을 진행 한다. 처음 세팅을 해주기 위한 호스트의 값, 주소, 포트 번호와 같은 값들을 가져와 정의해둔다.

string host = Dns.GetHostName(); // 내 로컬 컴퓨터의 호스트 이름
IPHostEntry iPHost = Dns.GetHostEntry(host);

//구글 같이 트래픽이 많은 곳은 아이피가 여러개이기에 배열
IPAddress iPAddress = iPHost.AddressList[0];
// 2222는 포트 번호 (클라이언트가 접속하는 번호와 같아야함)
// 식당 비유: iPAddress(식당 주소), 2222(식당 정문/후문)
IPEndPoint iPEndPoint = new IPEndPoint(iPAddress, 2222);  

🚧 결합 및 대기

listen을 하기 위한 소켓을 생성 한뒤, 위에서 정의한 정보들을 Binding(결합) 해준 후 최대 대기수를 설정한다.


Socket listenSocket = 
new Socket(endPoint.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);

// 문지기 교육
listenSocket.Bind(endPoint);

// 영업 시작
// backlog = Listen(최대 대기수) 초과 시 fail 뜸
listenSocket.Listen(10);

⚙ 클라이언트 접속 및 새 소켓 생성

이제 영업을 한 준비가 된 식당 처럼 Client를 받을 준비가 됐다. 일단 받았다고 가정하고, 다음 코드를 미리 작성한다.

// 접속을 할 때 까지 대기하기 위한 while
while(true)
{
  // to User
  Console.WriteLine("Listening .... ");

  // listen을 통해 받은 소켓을 입력	
  Socket ClientSocket = listen.Accept();
}

🤨 클라이언트의 요청 받기

우선 고객이 접속 시에 나에게 요구하는 말을 듣고, 그 다음 내가 해야할 말을 할 것이다.

// 얼마나 많은 말을 할지 모르기에 큰 배열로 잡고
byte[] recvBuff = new byte[1024];

// recvBytes에는 몇 바이트가 담겼는지가 담김다. 
// clientSocket.GetBytes(recvBuff)를 통해
// recvBuff에 실제 정보가 담긴다.
int recvBytes = clientSocket.GetBytes(recvBuff);

// 담겨진 정보를 Encoding하여 recvData에 담고 출력
string recvData = Encoding.UTF8.GetString(recvBuff, 0, recvBytes);
Console.WriteLine($"[From Client] {recvData}");

🤗 클라이언트에게 회신하기

// 보낸다
byte[] sendBuff = Encoding.UTF8.GetBytes("Welcome to Justin Server"); // 문자열을 바로 보낼 수 있는 타입으로 바꿔준거
clientSocket.Send(sendBuff);

// 끝낸다.
// 조금 더 우아하게 쫓아내는 방법? 나중에 알려줌
clientSocket.Shutdown(SocketShutdown.Both); 

clientSocket.Close();

😥 try catch로 혹시 모를 사고 대비


➰ 클라이언트 파트

🟦 기본 정의

클라이언트는 서버보다 적은 일을 하며, 기본 정의 과정은 같다.

 // DNS 
string host = Dns.GetHostName();
IPHostEntry iPHost = Dns.GetHostEntry(host); 
IPAddress ipAddr = iPHost.AddressList[0]; 
IPEndPoint endPoint = new IPEndPoint(ipAddr, 2222); 

// 손님 소켓 생성 
Socket socket = new 
Socket(endPoint.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);

🟦 메시지 보내기 및 받기

하지만 작동하는 순서는 다르다.

  • Connect()를 통해 endPoint 주소로 연결시킨다.

    예시이기에 이렇게 사용하는 거지, 실제로 이와 같이 사용시에는 오류가 날 수 있다.

// 입장 요청 endpoint 로 입장 문의를하는것
socket.Connect(endPoint);  // 주의 실제로 이러면 계속 대기함

// 어떤 녀석한테 연결 됐나 확인
Console.WriteLine
($"Connected To {socket.RemoteEndPoint.ToString()} ");
  • 보낼 메시지를 인코딩하여 byte 타입으로 담아서 send() 해준다
// 보낸다음 받을 예정
byte[] sendBuff = Encoding.UTF8.GetBytes("서버야.. 자니..?"); // string을 bytes 타입으로 변경
int sendBytes = socket.Send(sendBuff); // 주의 실제로 이러면 계속 대기함
  • 서버에서 받은 거 처럼 크기, 받을 공간을 설정하고 Receive() 를 통해 받는다.
// 받는다 서버가 나한테 얼마나 보낼지 모르늬 크게 만든다
byte[] recvBuff = new byte[1024]; 
int recvBytes = socket.Receive(recvBuff); // 주의 실제로 이러면 계속 대기함
string recvData = Encoding.UTF8.GetString(recvBuff, 0, recvBytes);
Console.WriteLine($"[From Server ] {recvData}");

// 닫는다.
socket.Shutdown(SocketShutdown.Both);
socket.Close();

지속적으로 요청 할 필요가 없으니 while은 사용하지 않고 try catch 구문만 사용하여 예외 처리를 해준다.

솔루션 -> 여러개의 시작 프로젝트에서 Server와, DummyClient 두개의 프로젝트만 시작으로 설정 해준다.

처음 보시는 분을 위해 잠깐 설명하자면, 이 프로젝트의 구조는 총 3개의 프로젝트로 구분되어있으며 각각 서버, 클라이언트, 서버의 핵심 기능들을 담아 둘 클래스와 같은 식으로 구분하고 있다.

🔶 실행 결과

실행을 해보면 이렇게 서버에게는 서버야..자니..? 라는 메시지가 온걸 볼 수 있고, 클라이언트엔느 연결됐다는 메시지와 함께 서버에서의 인사가 와있다.


📈 오늘 정리

처음에는 굉장히 복잡해보였지만, 어떤 구조로 작동하는지 순서를 보니 생각보다 쉽게 잘 이해가 됐고, 이제 통신하는 걸 볼 수 있으니까 재미있게 느껴진다. 굳

profile
인디 게임을 만들며 공부하고 있습니다.
post-custom-banner

0개의 댓글