C# Rookiss Part4 게임서버 : 소켓 프로그래밍 입문
🙇♀️소켓프로그래밍
- Session : 대리인 휴대폰
- Socket : 손님 휴대폰
- ListenerSocket : 문지기
- Bind : 문지기 교육
- Listen : 영업 시작
-
Accept : 안내
- 식당
- 문지기 고용
- 문지기 교육 - 식당의 주소기입, 입구가 어디인지, 핸드폰하나를 챙겨줌(손님의 문의 연락을 대기)
- 영업 시작
- 안내 - 대리인의 자격으로 한명한 테이블로 안내해줌, 식당이 대리인한테 핸드폰을 줌, 문의를 준 손님이랑 소통할 수 있는 핸드폰 (대리인 - 손님 소통가능)
- 손님
- 손님 관점
- 입장 문의 - 핸드폰으로 문의, 주소입력
- 대리인 입장 - 허가 받으면 대리인을 보냄 - 대리인의 폰엔 손님 폰(주소)를 넣음
문지기는 입구컷을 담당하고, 손님과 대리인을 연결시켜주는 역할
- 요약
1) 핸드폰 - 1. 소켓 2) 식당 번호로 입장 문의 - 2. 서버 주소로 Connect ( 소켓을 통해서)
휴대폰을 통해 대리인 휴대폰과 통화 가능 - 소켓을 통해 Session 소켓과 패킷 송수신 가능
1) 문지기 교육 - 1. Listener 소켓 준비 2) 문지기 교육 ( 식당 번호 알려줌 ) - 2. Bind (서버 주소/Port를 소켓에 연동) 3) 영업 시작 - 3. Listen 4) 안내 - 4. Accept
🪐식당
DNS (Domain Name System) www.google.com = 123.1.2.3 여러개의 ip를 가질수있음 dns서버는 네트워크 망안에 하나 더 있다
IPEndPoint - 식당 최종 주소 AddressFamily - IPv4, IPv6선택하는 것 , endPoint에 들어가 있음 SocketType.Stream, ProtocolType.Tcp는 세트
clientSocket.Receive()는 byte[]를 인자로 받음
Encoding.UTF8.GetString(recvBuff, 0, recvBytes);는 UTF8 규약으로 인코딩을 하고 있고 영어는 1바이트, 한글은 2바이트를 소모함, recvBuff - 받을 리시브, 0 - 첫 인덱스, recvBytes - 크기, string으로 반환함
리시브는 바이트를 공간을 받아서 스트링으로 변환해서 받음
샌드는 스트링을 그대로 보냄
🪐손님
// 문지기한테 입장 문의
socket.Connect()는 상대방의 최종주소를 기입
RemoteEndPoint는 연결한 반대쪽 대상 주소를 가르킴
🪐ServerCore
class Program
{
static void Main(string[] args)
{
// DNS (Domain Name System)
string host = Dns.GetHostName(); // 도메인 이름 정하기
IPHostEntry ipHost = Dns.GetHostEntry(host); // 도메인 이름 기입
IPAddress ipAddr = ipHost.AddressList[0]; // ip주모 가져오기 (우리는 첫번째꺼 하나만 쓸거기때문에 0)
IPEndPoint endPoint = new IPEndPoint(ipAddr, 7777); // 주소와 주소입구 알려주기
// 문지기
Socket listenSocket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); // 문지기 생성
// SocketType.Stream, ProtocolType.Tcp은 세트!
// Ucp도 있는데 디따 빠르지만 안전 x
// Tcp는 안전안전
try
{
// 문지기 교육
listenSocket.Bind(endPoint); // Bind함수로 교육(endPint를 넣어주어 주소와 입구 알려주기)
// 영업 시작
// BackLog : 최대 대기수
listenSocket.Listen(10); // Listen으로 영업시작
while (true)
{
Console.WriteLine("Listening...");
// 손님을 입장 시킨다
Socket clientSocket = listenSocket.Accept(); // 입장시킬 손님
// 받는다
byte[] recvBuff = new byte[1024];
int recvBytes = clientSocket.Receive(recvBuff); // Receive로 받지만 byte[]가 필요해서 만들어줌
string recvData = Encoding.UTF8.GetString(recvBuff, 0, recvBytes); // 인코딩을 함 (인코딩을 잘모르겠음)
// recvBuff, 0, recvBytes은 전달할 내용, 첫 인덱스 설정, 진짜 내용 대충 이런 뜻인듯..
Console.WriteLine($"[From Client] {recvData}");
// 보낸다
byte[] sendBuff = Encoding.UTF8.GetBytes("Welcome to MMORPG Server!"); // Send에 필요한 byte[]
clientSocket.Send(sendBuff); // Send로 보냄
// 쫓아낸다
clientSocket.Shutdown(SocketShutdown.Both); // 이거해주면 안전함. 안해줘도 됨
clientSocket.Close(); // 문닫아용
}
}
catch(Exception e) // 혹시 모를 예외처리
{
Console.WriteLine(e.ToString());
}
}
}
🪐DummyClient
class Program
{
static void Main(string[] args)
{
while (true)
{
// DNS (Domain Name System)
string host = Dns.GetHostName();
IPHostEntry ipHost = Dns.GetHostEntry(host);
IPAddress ipAddr = ipHost.AddressList[0];
IPEndPoint endPoint = new IPEndPoint(ipAddr, 7777); // 주소 입구가 같아야 되는게 포인트!
// 서버랑 같음
// 휴대폰 설정
Socket socket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
try
{
// 문지기한테 입장 문의
socket.Connect(endPoint); // Connect로 문의 드려요~
Console.WriteLine($"Connected to {socket.RemoteEndPoint.ToString()}");
// 보낸다
byte[] sendBuff = Encoding.UTF8.GetBytes("Hello World!");
int sendBytes = socket.Send(sendBuff); // 클라는 먼저 Send부터 보냄
// 받는다
byte[] recvBuff = new byte[1024];
int recvBytes = socket.Receive(recvBuff); // Receive로 받기
string recvData = Encoding.UTF8.GetString(recvBuff, 0, recvBytes);
Console.WriteLine($"[From Server] {recvData}");
// 나간다
socket.Shutdown(SocketShutdown.Both);
socket.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Thread.Sleep(500);
}
}
}