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를 했을 때 성공을 못하면 계속 대기를 해야하기 때문에 위험
//
}
}
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());
}
}
}
}