TCP/IP라는 단어를 네트워크 관련 책을 공부하면서 꼭 한번 들어본 키워드입니다.
많이 들어는 봤지만 TCP/IP관련 코드를 직접 구현해 본 적이 없습니다.
아무래도 웹 개발을 하면서 HTTP 통신 위주로만 공부를 해서 그런 것 같습니다.
이번에 게임 서버 프로그래머를 준비하면서 TCP/IP 소켓 프로그래밍을 사용해 서버를 구현했습니다.
게임 서버를 구축하는 과정에서 배운 개념과 내용을 글과 코드로 작성해봤습니다.
컴퓨터 네트워크에서 통신하는 데 사용되는 소프트웨어 개발 기술이며, 주로 인터넷을 통한 통신에 사용됩니다. 이 기술은 소켓(Socket)을 이용하여 데이터를 주고받는 방식으로 작동합니다.
소켓 프로그래밍에서 알아야 할 기본적인 키워드는 5 가지 입니다.
네트워크 통신을 위한 종단점(endpoint)으로, 소켓을 통해 데이터를 읽고 쓸 수 있습니다.
소켓은 주로 IP 주소와 포트 번호의 조합으로 식별됩니다.
서버(Server)
네트워크를 통해 클라이언트 요청에 응답하는 프로그램 또는 컴퓨터입니다.
서버는 특정 포트에서 클라이언트의 연결을 받아들이고, 요청에 따라 응답합니다.
클라이언트(Client)
서버에 연결하여 특정 서비스를 요청하는 프로그램 또는 컴퓨터입니다.
클라이언트는 서버에 요청을 보내고, 서버로부터 응답을 받습니다.
TCP(Transmission Control Protocol)
연결 지향적인 프로토콜로, 데이터의 신뢰성을 보장하며 순서를 유지합니다.
TCP 소켓은 클라이언트와 서버 간에 신뢰성 있는 양방향 통신을 제공합니다.
UDP(User Datagram Protocol)
연결이 없는 프로토콜로, 데이터 전송에 대한 신뢰성은 낮지만 빠른 속도를 제공합니다.
UDP 소켓은 데이터를 패킷 단위로 전송합니다.
TCP/IP는 컴퓨터 네트워크에서 데이터 통신을 위한 프로토콜 스택이며, 인터넷을 비롯한 많은 네트워크에서 사용됩니다. 데이터를 안정적으로 전송하기 위한 표준 프로토콜이며, 주로 클라이언트와 서버 간의 통신에 사용됩니다.
TCP 프로토콜의 작동은 크게 세 가지 흐름으로 구분한다.
3 Way-Handshake
4 Way-Handshake
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace BasicSocketServer
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Basic TCP Server");
StartListening();
}
public static void StartListening()
{
// (1) 소켓 객체 생성 (TCP 소켓)
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
// (2) 엔드포인트에 소켓 바인드(Bind)
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 7000);
listener.Bind(localEndPoint);
// (3) Listen소켓의 대기열의 길이를 설정합니다.
listener.Listen(10);
Console.WriteLine("Waiting for a connection...");
// (4) 연결을 받아들여 새 소켓 생성
Socket handler = listener.Accept();
// 클라이언트로부터 데이터를 받기 위한 버퍼(Buffer) 바이트 배열 초기화
byte[] bytes = new byte[8192];
Console.WriteLine("Client Connected...");
while (true) // 키 누르면 종료
{
// (5) 소켓 수신(Receive)
int bytesRec = handler.Receive(bytes);
// 클라이언트로부터 받은 데이터를 UTF8 string으로 인코딩합니다
string data = Encoding.UTF8.GetString(bytes, 0, bytesRec);
Console.WriteLine("Text received : {0}", data);
if (data.Equals("Quit"))
{
Console.WriteLine("Client Disconnected");
break;
}
// (6) 소켓 송신
handler.Send(bytes, 0, bytesRec, SocketFlags.None); // echo
}
// (7) 소켓 닫기
handler.Close();
listener.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
}
}
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace BasicSocketClient
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Baisc TCP Client");
StartClient();
}
private static void StartClient()
{
// (1) 소켓 객체 생성 (TCP 소켓)
Socket sender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
// (2) 서버의 엔드포인트 값을 객체를 생성하고 서버에 연결 시도
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 7000);
sender.Connect(remoteEP);
string cmd = string.Empty;
// 서버로부터 데이터를 받기 위한 버퍼(Buffer) 바이트 배열 초기화
byte[] receiverBuff = new byte[8192];
Console.WriteLine("Connected... Enter Quit to exit");
while (true)
{
// 서버에 보낼 문자열 데이터를 콘솔에 입력
cmd = Console.ReadLine();
// 콘솔에 입력된 문자열을 바이트 배열로 인코딩
byte[] buff = Encoding.UTF8.GetBytes(cmd);
// (3) 서버에 데이터 전송(Send)
int bytesSent = sender.Send(buff);
// (4) 서버에서 데이터 수신(Receive)
int bytesRec = sender.Receive(receiverBuff);
// 서버에서 받은 데이터 UTF8로 인코딩해서 콘솔에 출력
Console.WriteLine("Echoed test = {0}", Encoding.UTF8.GetString(receiverBuff, 0, bytesRec));
// 콘솔에 Quit를 입력 시 반복문 종료
if (cmd.Equals("Quit"))
{
break;
}
}
// (5) 소켓 닫기
sender.Shutdown(SocketShutdown.Both);
sender.Close();
}
catch (ArgumentNullException ane)
{
Console.WriteLine("ArgumentNullException : {0}", ane.ToString());
}
catch (SocketException se)
{
Console.WriteLine("SocketException : {0}", se.ToString());
}
catch (Exception ex)
{
Console.WriteLine("Unexpected exception : {0}", ex.ToString());
}
}
}
}