League Of Legends - Link Select [03์ฃผ์ฐจ] ๋„คํŠธ์›Œํ‚น - 1
๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿค“ Study/Game Server

[03์ฃผ์ฐจ] ๋„คํŠธ์›Œํ‚น - 1

by GAMEMING 2024. 4. 1.
728x90

 

 

 

ํ•œ๊ตญ๊ณตํ•™๋Œ€ํ•™๊ต ์ •๋‚ดํ›ˆ ๊ต์ˆ˜๋‹˜ 4-1 ๊ฒŒ์ž„ ์„œ๋ฒ„ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์ˆ˜์—… ์ค‘ ์ผ๋ถ€์ž…๋‹ˆ๋‹ค.

 


 

 

- ๋„คํŠธ์›Œํฌ ํ”„๋กœ๊ทธ๋ž˜๋ฐ (์†Œ์ผ“ ํ”„๋กœ๊ทธ๋ž˜๋ฐ)

 : ํ”„๋กœ์„ธ์Šค๋“ค๋ผ๋ฆฌ ๋„คํŠธ์›Œํฌ๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ  ๋ฐ›๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ

 : ํŒŒ์ผ I/O์™€ ๊ฑฐ์˜ ๋น„์Šทํ•œ ์–‘์ƒ → Open, Close, Read, Write

 : ๋„คํŠธ์›Œํฌ I/O → Connect(Accept), Close(CloseSocket0, Recv, Send, ๋ฒ„ํผ๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ  ๋ฐ›์œผ๋ฉฐ, ํŒŒ์ผ ์ด๋ฆ„ ๋Œ€์‹  Socket์ด๋ผ๋Š” ๋‹จ์–ด ์‚ฌ์šฉ

 : ์ฐจ์ด์ ์€ → ํŒŒ์ผ ์ด๋ฆ„ ๋Œ€์‹  ๋„คํŠธ์›Œํฌ ์ฃผ์†Œ ์‚ฌ์šฉ, ์„œ๋ฒ„์˜ ๊ฒฝ์šฐ ์–ด๋А ์ฃผ์†Œ์—์„œ ์—ฐ๊ฒฐ ์š”์ฒญ ์˜ฌ์ง€ ์•Œ ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ๊ฐ€ ๅคš

 : Recv ํ˜ธ์ถœ ํ›„ ๋งŽ์ด ๊ธฐ๋‹ค๋ฆฌ๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์œผ๋ฉฐ ๋ฒ„ํผ๊ฐ€ ๋‹ค ์ฑ„์›Œ์ง€์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๊ฐ€ ๅคš

 

 

 

- 4๊ณ„์ธต

 : ์ธํ„ฐ๋„ท์€ 4๊ฐœ์˜ ๋ ˆ์ด์–ด๋กœ ๊ตฌํ˜„

 1) Application : ์šฐ๋ฆฌ๊ฐ€ ์ž‘์„ฑํ•˜๋Š” ํ”„๋กœ๊ทธ๋žจ,

 2) Transport : Application์— ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•ด์ฃผ๋Š” API → TCP/UDP

 3) Network : ๋ฐ์ดํ„ฐ๋ฅผ ๋ชฉ์ ์ง€๊นŒ์ง€ ์•ˆ๋‚ดํ•˜๋Š” ์‹œ์Šคํ…œ → IPv4, IPv6

 4) Data Link : ์ปดํ“จํ„ฐ ์‚ฌ์ด๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” ๋ฌผ๋ฆฌ์  ๊ทœ๊ฒฉ → WiFi, Ethernet ...

 

 

 

- ํŒจํ‚ท(Packet)

 : ์ธํ„ฐ๋„ท ํ‘œ์ค€์—์„œ์˜ ํŒจํ‚ท ๊ฐ ๋ ˆ์ด์–ด์—์„œ ๋‹ค๋ฃจ๋Š” ๋ฐ์ดํ„ฐ ๋‹จ์œ„, ๊ฐ ๋ ˆ์ด์–ด์— ํ•„์š”ํ•œ ์ •๋ณด๊ฐ€ ์ถ”๊ฐ€๋จ(ํ—ค๋”), ํŒจํ‚ท์€ ๋…๋ฆฝ์ .

 : Application์—์„œ์˜ ํŒจํ‚ท   MMO ํŒจํ‚ท

 : MMO ํŒจํ‚ท   ์ข…๋ฅ˜๊ฐ€ ๋งŽ์Œ, ๋‹ค์Œ ํŒจํ‚ท ์˜ˆ์ธก ๋ถˆ๊ฐ€, ํŒจํ‚ท๋งˆ๋‹ค์˜ ํฌ๊ธฐ ๋‹ค๋ฆ„ ํŒจํ‚ท ์ˆ˜์‹  ์‹œ ํŒจํ‚ท์˜ ์ข…๋ฅ˜์™€ ํฌ๊ธฐ ์•Œ์•„์•ผ ํ•จ. 

 

 

 

- ํ”„๋กœํ† ์ฝœ

 : ํ”„๋กœํ† ์ฝœ → ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„ ์‚ฌ์ด ๋ฐ์ดํ„ฐ์˜ ํฌ๋งท๊ณผ ์ˆœ์„œ๋ฅผ ์ •์˜

 : ์ •์˜ ๋ฐฉ์‹

  1) Binary Format : Byte ๋‹จ์œ„๋กœ ๊ฐ’ ์˜๋ฏธ๋ฅผ ์ •์˜ → ๊ด€๋ฆฌ ์–ด๋ ค์šฐ๋‚˜ ์–ธ์–ด, OS, ์ปดํŒŒ์ผ๋Ÿฌ์— ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š์Œ

  2) Structure Format :  C์˜ ๊ตฌ์กฐ์ฒด ์ •์˜ํ•ด์„œ ๊ณต์œ  →๊ด€๋ฆฌ๊ฐ€ ์‰ฌ์šฐ๋‚˜, ์–ธ์–ด, OS, ์ปดํŒŒ์ผ๋Ÿฌ์— ์˜ํ–ฅ์„ ๋ฐ›์Œ

  3) SDK : ํ”„๋กœํ† ์ฝœ ์ •์˜์™€ ํ•ด์„์„ ๋„์™€์คŒ

: ํŒจํ‚ท ์žฌ ์กฐ๋ฆฝ → ์ธํ„ฐ๋„ท ํ‘œ์ค€์—์„œ์˜ ํŒจํ‚ท๊ณผ APP์—์„œ์˜ ํŒจํ‚ท์ด ๊ฐ™์ง€ ์•Š์Œ, ์ˆ˜์‹  ์ชฝ์—์„œ ์–ด๋–ป๊ฒŒ ํŒจํ‚ท์„ ๋ฐ›์•˜๋Š”์ง€ ์•Œ ์ˆ˜ ์—†์–ด์„œ ์žฌ ์กฐ๋ฆฝ์ด ํ•„์š”ํ•จ

 

 

 

- ์†Œ์ผ“ ํ”„๋กœ๊ทธ๋ž˜๋ฐ

 : ํŒŒ์ผ I/O์™€ ๋น„์Šท

 : Client Socket - Connect - Recv/Send - Close

 : Server Socket - Bind - listen - Accept - Recv/Send - Close

// Client

SOCKET s = socket(AF_INET, SOCK_STREAM, 0); // socket
sockaddr addr;
addr.sin_addr.s_addr = ...;
addr.sin_port = PORT;
connect(s, &addr, ...)   	// connect

...

sent = send(s, buf, size, flags);		// send
r_size = recv(s, buf, max_size, flags);		// recv

...

closesocket(s);			// closesocket




// Server
SOCKET s = socket(AF_INET, SOCK_STREAM, 0);	// socket
sockaddr c_addr;
c_addr.sin_port = PORT;
bind(s, &c_addr);		// bind
listen(s, 3);			// listen
sockaddr n_addr;							
SOCKET c = accept (s, &n_addr);		// accept

...

r_size = recv(c, buf, max_size, flags);		// recv
sent = send(c, buf, size, &sent, flags);	// send

...

closesocket(c);			// closesocket

 

 

 

 

- Windows Socket API

 : ๊ณ ์„ฑ๋Šฅ ๋„คํŠธ์›Œํฌ I/O๋ฅผ ์œ„ํ•ด์„œ๋Š” ์ „์šฉ API ํ•„์š” → WSASocket(), WSAConnect(), WSAAccept(), WSASend(), WSARecv()

 

// SOCKADDR ์ฃผ์†Œ ๊ตฌ์กฐ์ฒด
// ๋„คํŠธ์›Œํฌ ์ฃผ์†Œ๋ฅผ ์ €์žฅ
// IP์ฃผ์†Œ + PORT ๋ฒˆํ˜ธ(IP ์ฃผ์†Œใ… -> ์ปดํ“จํ„ฐ, PORT ๋ฒˆํ˜ธ -> ํ”„๋กœ์„ธ์Šค)


// ์„ ์–ธ
struct sockaddr addr;

addr.sin_family = AF_INET;
addr.sin_port = htons(SERVER_PORT);
inet_pton(AF_INET, SERVER_IP, &addr.sin_addr);
// SEVER_PORT๋Š” short, SERVER_IP๋Š” ๋ฌธ์ž์—ด

//////////////////////////////////////////////////////////

// WSABUF(gather/scatter I/O) :ํฉ์–ด์ง„ ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๊ตฌ์กฐ
// − ๋ฐ์ดํ„ฐ ๋ณต์‚ฌ(์„ฑ๋Šฅ ์ €ํ•˜ ์ฃผ๋ฒ”) ๊ฐ์†Œ

typedef struct __WSABUF
{ 
 	u_long len; 
 	char FAR *buf; 
} WSABUF, *LPWSAVUF;


// WSABUF๋ฅผ ์‚ฌ์šฉํ•œ ์ตœ์ ํ™”

// Move_p, Attack_p, Chat_p -> 3๊ฐœ์˜ ํŒจํ‚ท์„ ๋ณด๋‚ด์•ผ ํ•œ๋‹ค

// 1. ๊ธฐ์กด ๋‚ด๊ฐ€ ์•„๋Š” ๋ฐฉ์‹
// ์—ฌ๋Ÿฌ ๋ฒˆ์˜ ์‹œ์Šคํ…œ ํ˜ธ์ถœ์ด ํ•„์š”ํ•˜๋ฏ€๋กœ ์˜ค๋ฒ„ํ—ค๋“œ ๋ฐœ์ƒ
Send(s, &move_p. sizeof(move_p));
Send(s, &attack_p. sizeof(attack_p));
Send(s, &chat_p. sizeof(chat_p));


// 2
// ๋ฉ”๋ชจ๋ฆฌ ์ถ”๊ฐ€์‚ฌ์šฉ ๋ฐ ๋ฉ”๋ชจ๋ฆฌ ๋ณต์ œ-> ์˜ค๋ฒ„ํ—ค๋“œ
Char buf[1024]; int pos = 0;
Memcpy(buf, &move_p, sizeof(move_p)); pos+=sizeof(move_p);
Memcpy(buf + pos, &attack_p, sizeof(attack_p)); pos+=sizeof(attack_p);
Memcpy(buf + pos, &chat_p, sizeof(chat_p)); pos+=sizeof (chat_p);
Send(s, buf, pos);


// 3
WSABUF buf[3];
Buf[0].buf = &move_p;     buf[0].len = sizeof(move_p);
Buf[0].buf = &attack_p;   buf[0].len = sizeof(attack_p);
Buf[0].buf = &chat_p;     buf[0].len = sizeof(chat_p);
WSASend(s, buf, 3);
#include <iostream>
#include <WS2tcpip.h>   // header

// 1. Socket ๋งŒ๋“ค๊ธฐ

SOCKET WSASocket(int af, int type, int protocol,
	LPWSAPROTOCOL_INFO lpProtocolInfo, GROUP g, DWORO dwFlags)
    
// af : address family -> AF_INET ์‚ฌ์šฉ
// type : socket type -> SOCK_STREAM(TCP)
// protocol : ์‚ฌ์šฉํ•  ํ”„๋กœํ† ์ฝœ ์ข…๋ฅ˜ (IPPROTO_TCP/IPPROTO_UDP)
// lpProtocolInfo : protocol infomation (NULL)
// g : ์˜ˆ์•ฝ
// dwFlags : ์†Œ์ผ“ ์†์„ฑ (๋ณดํ†ต 0 or WSA_PROTOCOL_OVERLAPPED)



// 2. Socket ์—ฐ๊ฒฐ
// ๋Œ€๊ธฐํ•˜๊ณ  ์žˆ๋Š” ์ƒ๋Œ€ ์†Œ์ผ“์— ์ž์‹ ์˜ ์†Œ์ผ“ ์—ฐ๊ฒฐ

int WSAConnect(SOCKET s, const struct sockaddr* name,
	int namelen, LPWSABUF lpCallerData, LPWSABUF lpCalleeData,
    LPQOS lpSQOS, LPQOS lpGQOS)
    
// s : ์†Œ์ผ“
// name, namelen : ์ƒ๋Œ€ ์†Œ์ผ“ ์ฃผ์†Œ์™€ ์ฃผ์†Œ ๊ธธ์ด -> ๋ณดํ†ต sockaddr_in ๊ตฌ์กฐ์ฒด ์‚ฌ์šฉ
// lpCallerData : ์—ฐ๊ฒฐ ์š”์ฒญ ์‹œ์— ์ „์†กํ•  ๋ฐ์ดํ„ฐ์˜ ๋ฒ„ํผ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ํฌ์ธํ„ฐ -> ๋ณดํ†ต sizeof(struct sockaddr)
// lpCalleeData : ์—ฐ๊ฒฐ ์š”์ฒญ์— ๋Œ€ํ•œ ์‘๋‹ต์œผ๋กœ ๋ฐ›์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•  ๋ฒ„ํผ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ํฌ์ธํ„ฐ
// lpSQOS, lpGQOS : ํ’ˆ์งˆ ์„œ๋น„์Šค(Quality of Service, QoS) ์š”๊ตฌ ์‚ฌํ•ญ ์ง€์ • ํฌ์ธํ„ฐ



// 3. Socket์—์„œ ๋ฐ์ดํ„ฐ ๋ฐ›๊ธฐ

int WSARecv(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, 
	LPDWORD lpNumberofBytesRecvd, LPDWORD lpFlags,
    LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
    
// s : ์†Œ์ผ“
// lpBuffers : ๋ฐ›์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•  ๋ฒ„ํผ
// dwBufferCount : ๋ฒ„ํผ ๊ฐœ์ˆ˜
// lpFlags : ๋™์ž‘ ์˜ต์…˜ (MSG_PEEK, MSG_OOB)
// - MSG_PEEK : ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์‹ ํ•  ๋•Œ, ๋ฒ„ํผ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ œ๊ฑฐํ•˜์ง€ ์•Š๊ณ  ๋ฐ์ดํ„ฐ๋ฅผ ํ™•์ธ ๊ฐ€๋Šฅ, ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฒ„ํผ์—์„œ ์ œ๊ฑฐX
// - MSG_OOB : ๊ธด๊ธ‰(out-of-band) ๋ฐ์ดํ„ฐ๋ฅผ ์†Œ์ผ“์œผ๋กœ๋ถ€ํ„ฐ ์ฝ๊ฑฐ๋‚˜ ์ „์†ก
// lpNumberofBytesRecvd : ๋ฐ›์€ ๋ฐ์ดํ„ฐ ํฌ๊ธฐ
// lpOverlapped, lpCompletionRoutine : ๋’ค์— ์„ค๋ช…



// 4. Socket ๋Š๊ธฐ

int closesocket(SOCKET s)

// s : ์†Œ์ผ“
// return value : 0 (success)



// 5. PORT ๋ฌถ๊ธฐ
// ํฌํŠธ๋ฅผ ์„ ์ ํ•ด ๋‹ค๋ฅธ ํ”„๋กœ๊ทธ๋žจ์ด ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•˜๋„๋ก ํ•จ

int bind(SOCKET s, const struct sockaddr* name, int namelen)

// s : ์†Œ์ผ“
// name, namelen :  ์ƒ๋Œ€ ์†Œ์ผ“ ์ฃผ์†Œ์™€ ์ฃผ์†Œ ๊ธธ์ด
//  - INADDR_ANY : ์ „์ฒด ์ฃผ์†Œ๋กœ๋ถ€ํ„ฐ ์ ‘์† ํ—ˆ์šฉ
//  - info.sin_affr.S_in.S_addr = htonl(INADDR_ANY)
//  - htonl : ํ˜ธ์ŠคํŠธ ๋ฐ”์ดํŠธ ์ˆœ์„œ๋ฅผ ๋„คํŠธ์›Œํฌ ๋ฐ”์ดํŠธ ์ˆœ์„œ๋กœ ๋ณ€ํ™˜



// 6. Socket ์ ‘์† ๋Œ€๊ธฐ
// ์†Œ์ผ“ ์ ‘์†์„ ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š” ์ƒํƒœ

int listen(SOCKET s, int backlog)

// s : ์†Œ์ผ“
// backlog : ์ ‘์† ๋Œ€๊ธฐ ํ์˜ ์ตœ๋Œ€ ์—ฐ๊ฒฐ ๊ฐ€๋Šฅ ์ˆซ์ž 
//  - ์„œ๋ฒ„์— ๋„์ฐฉ ํ›„ accept๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ๊ณ  ์žˆ๋Š” ์†Œ์ผ“ ์—ฐ๊ฒฐ์˜ ์ตœ๋Œ€ ์ˆ˜
//  - ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ ํ”„๋กœ๊ทธ๋žจ์—์„œ๋Š” 5์ •๋„๊ฐ€ ์ ๋‹น, ๋Œ€์šฉ๋Ÿ‰ ์„œ๋ฒ„๋Š” 20-200 or SOMAXCONN



// 7. ์—ฐ๊ฒฐ Socket ์ƒ์„ฑ
// ์—ฐ๊ฒฐ๋œ ์†Œ์ผ“์„ ๋งŒ๋“ฆ

SOCKET WSAAccept(SOCKET s, struct sockaddr* name, LPINT addrlen,
				LPCONDITIONPROC lpfnCondition, DWORD dwCallbackData)

// s : listen์„ ํ•˜๊ณ  ์žˆ๋Š” ์†Œ์ผ“
// name, addrlen : ์—ฐ๊ฒฐ๋œ ์ƒ๋Œ€ ์†Œ์ผ“ ์ฃผ์†Œ
// lpfnCondition : ์—ฐ๊ฒฐ ๊ฑฐ์ ˆ์„ ํŒ๋‹จํ•˜๋Š” ํ•จ์ˆ˜ (NULL)
// dwCallbackData : lpfnCondition์— ๋“ค์–ด๊ฐˆ ๊ฐ’
// Return value : ๋ฐ์ดํ„ฐ ์ „์†ก์šฉ ์†Œ์ผ“



// ๋””๋ฒ„๊น… tip
void error_display(const char *msg, int err_no )
{
	WCHAR *lpMsgBuf;
	FormatMessage(
		FORMAT_MESSAGE_ALLOCATE_BUFFER |
		FORMAT_MESSAGE_FROM_SYSTEM,
		NULL, err_no,
		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
		(LPTSTR)&lpMsgBuf, 0, NULL );
	std::cout << msg;
	std::wcout << L" ์—๋Ÿฌ " << lpMsgBuf << std::endl;
	while(true); // ๋””๋ฒ„๊น…
	LocalFree(lpMsgBuf);
}

// + ํ•œ๊ธ€
std::wcout.imbue(std::locale("korean"));

 

 

 

- ๊ฐ„๋‹จํ•œ ์‹ค์Šต (Echo 1๋Œ€1)

// Client

#include <iostream>
#include <WS2tcpip.h>

#pragma comment (lib, "WS2_32.LIB")

constexpr short PORT = 4000;
constexpr char SERVER_ADDR[] = "127.0.0.1";
constexpr int BUFSIZE = 256;

int main()
{
	std::wcout.imbue(std::locale("korean"));

	WSADATA WSAData;
	WSAStartup(MAKEWORD(2, 2), &WSAData);

	SOCKET server_s = WSASocket(AF_INET, SOCK_STREAM,
		IPPROTO_TCP, nullptr, 0, 0);

	SOCKADDR_IN server_a;
	server_a.sin_family = AF_INET;
	server_a.sin_port = htons(PORT);
	inet_pton(AF_INET, SERVER_ADDR, &server_a.sin_addr);

	connect(server_s, reinterpret_cast<sockaddr*>(&server_a), sizeof(server_a));

	// reinterpret_cast<type_id>(expression);
	//  type_id: ๋ฐ”๊ฟ€ ํƒ€์ž… / expression : ๋Œ€์ƒ
	// ํฌ์ธํ„ฐ -> ํฌ์ธํ„ฐ, ํฌ์ธํ„ฐ -> ์ผ๋ฐ˜ ๋ณ€์ˆ˜, ์ผ๋ฐ˜ ๋ณ€์ˆ˜ -> ํฌ์ธํ„ฐ, ์ž๋ฃŒํ˜• -> ๋‹ค๋ฅธ ์ž๋ฃŒํ˜•

	// connect ํ•จ์ˆ˜๋Š” sockaddr ๊ตฌ์กฐ์ฒด๋ฅผ ์š”๊ตฌํ•˜๋ฏ€๋กœ,
	// reinterpret_cast๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ server_a๋ฅผ sockaddr* ํƒ€์ž…์œผ๋กœ ๋ณ€ํ™˜

	while (true) {
		char buf[BUFSIZE];
		std::cout << "Enter Message : ";
		std::cin.getline(buf, BUFSIZE);     // enter๊ธฐ์ค€ getline

		WSABUF wsabuf[1];
		wsabuf[0].buf = buf;
		wsabuf[0].len = static_cast<int>(strlen(buf)) + 1;

		if (wsabuf[0].len == 0)
			break;

		DWORD sent_size;
		WSASend(server_s, wsabuf, 1, &sent_size, 0, nullptr, nullptr);

		wsabuf[0].len = BUFSIZE;  // ์–ผ๋งˆ๋‚˜ ์˜ฌ์ง€ ๋ชจ๋ฅด๋‹ˆ ์ตœ๋Œ€ ์‚ฌ์ด์ฆˆ
		DWORD recv_size;
		DWORD recv_flag = 0; // ์ดˆ๊ธฐํ™” ํ•„์ˆ˜
		WSARecv(server_s, wsabuf, 1, &recv_size, &recv_flag, nullptr, nullptr);

		for (DWORD i = 0; i < recv_size; ++i)
			std::cout << buf[i];

		std::cout << std::endl;
	}
	closesocket(server_s);
	WSACleanup();
}



// Server
#include <iostream>
#include <WS2tcpip.h>

#pragma comment (lib, "WS2_32.LIB")

constexpr short PORT = 4000;
constexpr int BUFSIZE = 256;

void print_error(const char* msg, int err_no)
{
	// ์ถœ๋ ฅ ๋ฉ”์„ธ์ง€๋ฅผ ์ €์žฅํ•  buf
	WCHAR* msg_buf;
	FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
		NULL, err_no, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<LPWSTR>(&msg_buf), 0, NULL);
	std::cout << msg;
	std::wcout << L" : ์—๋Ÿฌ : " << msg_buf;
	while (true);   // ๋””๋ฒ„๊น…
	LocalFree(msg_buf);
}

int main()
{
	WSADATA WSAData;
	WSAStartup(MAKEWORD(2, 2), &WSAData);
	SOCKET server_s = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, nullptr, 0, 0);
	SOCKADDR_IN server_a;
	server_a.sin_family = AF_INET;
	server_a.sin_port = htons(PORT);
	server_a.sin_addr.S_un.S_addr = htons(INADDR_ANY);

	bind(server_s, reinterpret_cast<sockaddr*>(&server_a), sizeof(server_a));
	listen(server_s, SOMAXCONN);

	int addr_size = sizeof(server_a);
	SOCKET client_s = WSAAccept(server_s, reinterpret_cast<sockaddr*>(&server_a), &addr_size, nullptr, 0);
	std::cout << "์„ฑ๊ณต : " << server_a.sin_port << std::endl;

	while (true) {
		char buf[BUFSIZE];

		WSABUF wsabuf[1];
		wsabuf[0].buf = buf;
		wsabuf[0].len = BUFSIZE; // ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ์–ผ๋งˆ ์˜ฌ์ง€ ๋ชจ๋ฅด๋‹ˆ ์ตœ๋Œ€ ์‚ฌ์ด์ฆˆ
		DWORD recv_size;
		DWORD recv_flag = 0; //์ดˆ๊ธฐํ™” ์•ˆํ•˜๋ฉด ์ด์ƒํ•˜๊ฒŒ ๋ฐ›์œผ๋ ค ํ•จ
		int res = WSARecv(client_s, wsabuf, 1, &recv_size, &recv_flag, nullptr, nullptr);

		if (res != 0) {
			print_error("WSARecv", WSAGetLastError());
		}

		if (recv_size == 1)
			break;

		std::cout << "Client Sent : ";
		for (DWORD i = 0; i < recv_size; ++i)
			std::cout << buf[i];

		std::cout << std::endl;

		wsabuf[0].len = recv_size;

		DWORD sent_size;
		WSASend(client_s, wsabuf, 1, &sent_size, 0, nullptr, nullptr);
	}

	closesocket(server_s);
	closesocket(client_s);
	WSACleanup();

}