소켓 프로그래밍 기초
소켓 프로그래밍도 식당의 예를 들어서 설명할 수 있다. 운영할 준비가 된 식당이 있다고 가정하자. 식당에는 문과 문지기가 있고, 손님은 이 식당의 문지기에게 휴대폰으로 식당에 자리가 있는지 물어보고, 자리가 있으면 친구를 먼저 보내서 상황을 전달 받을 수 있다.
손님의 입장 (클라이언트)
- 휴대폰 : 소켓
- 손님 : 클라이언트
- 친구 : 클라이언트 Session
- 식당 번호로 입장 문의 : 서버 주소로 연결
- 휴대폰을 통해 친구와 연락 : 소켓을 통해 Session 소켓과 패킷 송수신 가능
클라이언트가 서버에 접속을 하면, 서버에서 기타 처리를 한 뒤, Session을 하나 만들어서 모든 통신은 이 Session을 통해 이루어진다.
식당의 입장 (서버)
- 문지기 고용 : Listen 소켓 준비
- 문지기 교육 (손님에게 식당 주소, 번호를 알려줌) : Bind (서버 주소/Port를 소켓에 연동)
- 영업 시작 (손님에게 문의 전화가 오면 알려줌): Listen
- 안내 : Accept
클라이언트 Session을 통해 클라이언트와 패킷 송수신 가능
소켓 프로그래밍 입문
기본 셋팅
다음과 같이 기본 셋팅을 해준다.
코드 작성
ServerCore
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
class Server
{
static void Main(string[] args)
{
//DNS(Domain Name System)
string host = Dns.GetHostName(); // 로컬 컴퓨터의 호스트 이름
IPHostEntry iphost = Dns.GetHostEntry(host);
IPAddress ipAddress = iphost.AddressList[0]; // 주소에 해당하는 IP가 여러개일 수 있음
IPEndPoint endPoint = new IPEndPoint(ipAddress, 7777); // 7777은 내가 설정한 포트 번호
// Listener 소켓 생성 (문지기의 휴대폰)
Socket listener = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); //TCP 사용
// 중간에 에러가 나는지 확인하기 위해 try-catch 사용
try
{
// 문지기 교육
listener.Bind(endPoint); // 포트 번호 입력
// 영업 시작
listener.Listen(10); // 최대로 대기할 수 있는 수, 넘으면 Fail
// 영업중
while (true)
{
Console.WriteLine("Server is listening on port 7777...");
// 손님을 입장 시킴 (클라이언트 연결)
Socket client = listener.Accept();
Console.WriteLine("Client connected.");
// 데이터 수신
byte[] buffer = new byte[1024]; // 몇개를 받을지 몰라서 넉넉하게
int bytesRead = client.Receive(buffer); // 몇 바이트를 받아왔는지
string receivedText = Encoding.UTF8.GetString(buffer, 0, bytesRead); // 인코딩 범위를 설정
Console.WriteLine($"Received: {receivedText}");
// 클라이언트에게 응답 보내기
string responseText = "Hello from server";
byte[] responseBytes = Encoding.UTF8.GetBytes(responseText); // 보내는 경우, 몇개를 보내는지 알 수 있다.
client.Send(responseBytes);
// 손님을 쫒아냄 (연결 종료)
client.Shutdown(SocketShutdown.Both); // 연결을 끊기전에 예고
client.Close();
}
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
}
* DNS (Domain Name System)
IP 주소를 도메인 주소(ex) 123.123.123.12 -> www.Jaemin.com) 로 변경해주는 것. IP 주소를 그대로 사용하게 되면 PC를 바꾸게 되었을 때, 서버의 주소가 변경 될 수도 있기에 도메인을 사용해야 한다.)
* IPAddress ipAddress
IP 주소를 뱉어준다. 주소에 해당하는 IP가 한개일 수도 있지만, 여러개 일 수도 있다. 트래픽이 큰 사이트의 경우 여러 사람들에게 다른 IP 주소를 알려줘서 분산을 해준다. 우리는 첫번째의 주소를 사용한다.
* IPEndPoint endPoint = new IPEndPoint(ipAddress, 7777);최종 주소.ipAddress는 식당 주소에 해당하고, 7777은 식당 문의 번호를 나타낸다. 7777이 아니라 다른 포트 번호로 접근하게 되면, 입장할 수 없다.
* Socket client = listener.Accept();입장한 손님과 대화를 하고 싶다면 이 소켓을 통해서 한다. 손님이 입장하지 않으면 밑 코드가 실행되지 않는다.
DummyClient
클라이언트는 서버보다는 적은 일을 하고, while문을 사용하지 않는 것과 순서를 제외하고는 거의 동일하다. DummyClient는 실제로 클라이언트와 서버 간의 통신 전, 임시로 테스트하기 위해 만드는 것이다.
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
class Client
{
static void Main(string[] args)
{
// 서버에 연결 (서버 코드와 동일)
//DNS(Domain Name System)
string host = Dns.GetHostName();
IPHostEntry iphost = Dns.GetHostEntry(host);
IPAddress ipAddress = iphost.AddressList[0];
IPEndPoint endPoint = new IPEndPoint(ipAddress, 7777);
// 휴대폰 설정
Socket client = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
try
{
// 문지기에게 입장 문의
client.Connect(endPoint);
Console.WriteLine("Connected to server.");
// 서버와 순서가 반대 (전송 -> 수신)
// 서버에 데이터 전송
string message = "Hello from client";
byte[] messageBytes = Encoding.UTF8.GetBytes(message);
client.Send(messageBytes);
// 서버로부터 응답 수신
byte[] buffer = new byte[client.ReceiveBufferSize];
int bytesRead = client.Receive(buffer);
string receivedText = Encoding.UTF8.GetString(buffer,0,bytesRead);
Console.WriteLine($"Received: {receivedText}");
// 연결 종료
client.Shutdown(SocketShutdown.Both);
client.Close();
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
}
client.Connect(endPoint); / client.Send(messageBytes); / int bytesRead = client.Receive(buffer);
실제 게임에서는 위 부분을 수정해야 한다. 서버에서 받아주지 않으면 각각 코드에서 멈추기 때문이다.
서버는 계속해서 클라이언트의 접속을 받아야 하기 때문에 while문을 사용했지만, 클라이언트는 한번만 서버에 접속하도록 while문을 사용하지 않았다.
'서버 > 서버 이론' 카테고리의 다른 글
Session 구현 (0) | 2025.04.13 |
---|---|
Listener 구현 (0) | 2025.04.12 |
네트워크 기초 이론 (0) | 2025.04.07 |
Thread Local Storage (TLS) (0) | 2025.04.06 |
Lock 구현 (0) | 2025.03.29 |