[C++] TCP Server

seunghyunยท2023๋…„ 7์›” 5์ผ
0

Server

๋ชฉ๋ก ๋ณด๊ธฐ
3/4

TCP ๐Ÿ†š UDP

TCP, UDP ๋Š” ์ „ํ™”์™€ ์ด๋ฉ”์ผ ์ฐจ์ด๋ผ๊ณ  ๋น„์œ ํ•  ์ˆ˜ ์žˆ๋‹ค.

์—ฐ๊ฒฐ์ง€ํ–ฅ์„ฑ

TCP๋Š” ์—ฐ๊ฒฐํ˜• ์„œ๋น„์Šค, UDP๋Š” ๋น„์—ฐ๊ฒฐํ˜• ์„œ๋น„์Šค๋ผ ํ•œ๋‹ค.

TCP ๋Š” ์—ฐ๊ฒฐ์„ ์œ„ํ•ด ํ• ๋‹น๋˜๋Š” ๋…ผ๋ฆฌ์ ์ธ ๊ฒฝ๋กœ๊ฐ€ ์žˆ๋‹ค.

  • ๋˜ํ•œ ์ „์†ก ์ˆœ์„œ๊ฐ€ ๋ณด์žฅ๋œ๋‹ค.

UDP ๋Š” ์—ฐ๊ฒฐ์ด๋ผ๋Š” ๊ฐœ๋…์ด ์—†๊ณ  ์ „์†ก ์ˆœ์„œ๊ฐ€ ๋ณด์žฅ๋˜์ง€ ์•Š๋Š”๋‹ค.

  • ๋˜ํ•œ ๊ฒฝ๊ณ„(Boundary)์˜ ๊ฐœ๋…์ด ์žˆ๋‹ค.
  • TCP ์ฒ˜๋Ÿผ ์—ฐ๊ฒฐ๋˜๋Š” ๊ฐœ๋…์ด ์•„๋‹ˆ๋ผ์„œ accept, connect ์˜ ๊ฐœ๋…์ด ์—†๋‹ค?

์†๋„์™€ ์‹ ๋ขฐ์„ฑ

TCP๋Š” ์‹ ๋ขฐ์„ฑ์€ ์ข‹์ง€๋งŒ ์†๋„๊ฐ€ (UDP์— ๋น„ํ•ด ์ƒ๋Œ€์ ์œผ๋กœ)๋А๋ฆฌ๋‹ค.

  • ๋ถ„์‹ค์ด ์ผ์–ด๋‚˜๋ฉด ์ฑ…์ž„์ง€๊ณ  ๋‹ค์‹œ ์ „์†กํ•œ๋‹ค.
  • ๋ฌผ๊ฑด์„ ์ฃผ๊ณ  ๋ฐ›์„ ์ƒํ™ฉ์ด ์•„๋‹ˆ๋ฉด ์ผ๋ถ€๋งŒ ๋ณด๋‚ธ๋‹ค. (ํ๋ฆ„/ํ˜ผ์žก์ œ์–ดโญ๏ธ)
  • ๊ณ ๋ คํ•  ๊ฒƒ์ด ๋งŽ์•„์„œ ์†๋„๊ฐ€ ๋А๋ฆฌ๋‹ค.
  • ๋А๋ฆฌ๋”๋ผ๋„ ๋งŽ์€ ์‚ฌ๋žŒ์„ ๊ณตํ‰ํ•˜๊ฒŒ

UDP๋Š” ์‹ ๋ขฐ์„ฑ์€ ๋‚˜์˜์ง€๋งŒ ์†๋„๊ฐ€ ๋น ๋ฅด๋‹ค.

  • ๋ถ„์‹ค์— ๋Œ€ํ•ด๋‚˜ ์ฑ…์ž„์ด ์—†์–ด์„œ ๋„คํŠธ์›Œํฌ ํ›ผ์† ๋ฌธ์ œ, ๋‚ญ๋น„๊ฐ€ ์‹ฌํ•ด์งˆ ์ˆ˜ ์žˆ๋‹ค
  • ์ผ๋‹จ ๋ณด๋‚ด๊ณ  ์ƒ๊ฐํ•œ๋‹ค.
  • ๋‹จ์ˆœํ•ด์„œ ์†๋„๊ฐ€ ๋น ๋ฅด๋‹ค.
  • ๋น ๋ฅด๊ฒŒ ํ•œ๋‘๋ช…

๋ฐ์ดํ„ฐ ๊ฒฝ๊ณ„ Boundary

TCP๋Š” ๊ฒฝ๊ณ„์˜ ๊ฐœ๋…์ด ์—†๋‹ค (์ˆœ์„œ๋Š” ๋ณด์žฅ๋˜์ง€๋งŒ ๊ฒฝ๊ณ„๊ฐ€ ์—†๋Š”, ์ปจ๋ฒ ์ด์–ด ๋ฒจํŠธ ๋А๋‚Œ)

UDP๋Š” ๊ฒฝ๊ณ„์˜ ๊ฐœ๋…์ด ์žˆ๋‹ค (์ˆœ์„œ๋Š” ๋ณด์žฅ๋˜์ง€ ์•Š์ง€๋งŒ ํƒ๋ฐฐ ํฌ์žฅ์ฒ˜๋Ÿผ ๊ฒฝ๊ณ„๊ฐ€ ๋”ฑ๋”ฑ ์žˆ๋‹ค)


TCP Server

winsock ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋งค์šฐ ๊ธฐ๋ณธ์ ์ธ ํ˜•ํƒœ์˜ TCP ์„œ๋ฒ„๋ฅผ ๊ตฌํ˜„ํ•ด๋ณธ๋‹ค. blocking ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋กœ์ปฌ ๋ฃจํ”„๋ฐฑ ์ฃผ์†Œ๋กœ ์—์ฝ” ์ฑ„ํŒ…์„ ํ•ด๋ณด์ž

๊ฐ„๋‹จํ•˜๊ฒŒ ์ •๋ฆฌํ•ด๋ณด๋ฉด ์ด๋Ÿฐ ํ˜•ํƒœ์ด๋‹ค

ํด๋ผ์ด์–ธํŠธ
1) ์†Œ์ผ“ ์ƒ์„ฑ (socket)
2) ์„œ๋ฒ„์— ์—ฐ๊ฒฐ ์š”์ฒญ (connect)
3) ํ†ต์‹  (send, receive)

์„œ๋ฒ„
1) ์ƒˆ๋กœ์šด ์†Œ์ผ“ ์ƒ์„ฑ (socket)
2) ์†Œ์ผ“์— ์ฃผ์†Œ/ํฌํŠธ ๋ฒˆํ˜ธ ์„ค์ • (bind)
3) ์†Œ์ผ“ ์ผ ์‹œํ‚ค๊ธฐ (listen)
4) ์†๋‹˜ ์ ‘์† (accept)
5) ํด๋ผ์™€ ํ†ต์‹  (send, receive)

Dummy Client

#include "pch.h"
#include <iostream>

// ํด๋ผ
// 1) ์ƒˆ๋กœ์šด ์†Œ์ผ“ ์ƒ์„ฑ
// 2) ์„œ๋ฒ„์— ์—ฐ๊ฒฐ ์š”์ฒญ
// 3) ์„œ๋ฒ„์™€ ํ†ต์‹ 
int main()
{
	WSAData wsaData;
	if (::WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
		return 0;

	// ad : Address Family (AF_INET = IPv4, AF_INET6 = IPv6)
	// type : TCP(SOCK_STREAM) vs UDP(SOCK_DGRAM)
	// protocol : 0
	// return : descriptor
	SOCKET clientSocket = ::socket(AF_INET, SOCK_STREAM, 0);
	if (clientSocket == INVALID_SOCKET)
		return 0;

	SOCKADDR_IN serverAddr; // IPv4
	::memset(&serverAddr, 0, sizeof(serverAddr));
	serverAddr.sin_family = AF_INET;
	//serverAddr.sin_addr.s_addr = ::inet_addr("127.0.0.1"); << deprecated
	::inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr);
	serverAddr.sin_port = ::htons(7777); // 80 : HTTP

	if (::connect(clientSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)
		return 0;

	// ---------------------------
	// ์—ฐ๊ฒฐ ์„ฑ๊ณต! ์ด์ œ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ ์†ก์ˆ˜์‹  ๊ฐ€๋Šฅ!
	cout << "Connected To Server!" << endl;

	while (true)
	{
		// TODO

		char sendBuffer[100] = "Hello! I am Client";
		int32 resultCode = ::send(clientSocket, sendBuffer, sizeof(sendBuffer), 0);
		if (resultCode == SOCKET_ERROR)
			return 0;

		char recvBuffer[100];
		int32 recvLen = ::recv(clientSocket, recvBuffer, sizeof(recvBuffer), 0);
		if (recvLen <= 0)
			return 0;

		cout << "Echo Data : " << recvBuffer << endl;

		this_thread::sleep_for(1s);
	}

	// --------------------------

	::closesocket(clientSocket);
	::WSACleanup();
}

Server

#include "pch.h"
#include <iostream>
#include <thread>
#include <vector>
using namespace std;
#include <atomic>
#include <mutex>
#include <windows.h>
#include "TestMain.h"
#include "ThreadManager.h"


// ์„œ๋ฒ„
// 1) ์ƒˆ๋กœ์šด ์†Œ์ผ“ ์ƒ์„ฑ (socket)
// 2) ์†Œ์ผ“์— ์ฃผ์†Œ/ํฌํŠธ ๋ฒˆํ˜ธ ์„ค์ • (bind)
// 3) ๋ฆฌ์Šจ ์†Œ์ผ“ ์ผ ์‹œํ‚ค๊ธฐ (listen)
// 4) ์ ‘์†๋œ ํด๋ผ์— ๋Œ€ํ•ด์„œ ์ƒˆ๋กœ์šด ์†Œ์ผ“์„ ์ƒ์„ฑ (accept)
// 5) ํด๋ผ์™€ ํ†ต์‹ 

int main()
{
	WSADATA wsaData;
	if (::WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
		return 0;

	// 1) ์†Œ์ผ“ ์ƒ์„ฑ
	// ad : Address Family (AF_INET = IPv4, AF_INET6 = IPv6)
	// type : TCP(SOCK_STREAM) vs UDP(SOCK_DGRAM)
	// protocol : 0
	// return : descriptor
	//int32 errorCode = ::WSAGetLastError();
	SOCKET listenSocket = ::socket(AF_INET, SOCK_STREAM, 0);
	if (listenSocket == 0)
		return 0;

	// 2) ์ฃผ์†Œ/ํฌํŠธ ๋ฒˆํ˜ธ ์„ค์ • (bind)
	// ์—ฐ๊ฒฐํ•  ๋ชฉ์ ์ง€๋Š”? (IP์ฃผ์†Œ + Port) -> XX ์•„ํŒŒํŠธ YY ํ˜ธ
	SOCKADDR_IN serverAddr; // IPv4
	::memset(&serverAddr, 0, sizeof(serverAddr));
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_addr.s_addr = ::htonl(INADDR_ANY); // ์•„๋ฌด IP๋‚˜
	serverAddr.sin_port = ::htons(7777); // 80 : HTTP

	// host to network short
	// Little-Endian vs Big-Endian
	// ex) 0x12345678 4๋ฐ”์ดํŠธ ์ •์ˆ˜
	// low [0x78][0x56][0x34][0x12] high < little
	// low [0x12][0x34][0x56][0x78] high < big = network

	if (::bind(listenSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)
		return 0;

	// 3) ์—…๋ฌด ๊ฐœ์‹œ (listen)
	if (::listen(listenSocket, SOMAXCONN) == SOCKET_ERROR)
		return 0;

	// 4) ์†๋‹˜ ๋งž์ด (accept)
	while (true)
	{
		SOCKADDR_IN clientAddr;
		::memset(&clientAddr, 0, sizeof(clientAddr));
		int32 addrLen = sizeof(clientAddr);
		
		SOCKET clientSocket = ::accept(listenSocket, (SOCKADDR*)&clientAddr, &addrLen);
		if (clientSocket == INVALID_SOCKET)
			return 0;

		// ์†๋‹˜ ์ž…์žฅ!
		char ip[16];
		::inet_ntop(AF_INET, &clientAddr.sin_addr, ip, sizeof(ip));
		cout << "Client Connected! IP = " << ip << endl;

		// 5) TODO
		while (true)
		{
			char recvBuffer[100];
			int32 recvLen = ::recv(clientSocket, recvBuffer, sizeof(recvBuffer), 0);
			if (recvLen <= 0)
				return 0;

			cout << "Recv Data : " << recvBuffer << endl;
			cout << "Recv Data Len : " << recvLen << endl;

			int32 resultCode = ::send(clientSocket, recvBuffer, recvLen, 0);
			if (resultCode == SOCKET_ERROR)
				return 0;
		}
	}

	::closesocket(listenSocket);
	::WSACleanup();
}

profile
๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป๐ŸŽฎ

0๊ฐœ์˜ ๋Œ“๊ธ€