MMOServer

TCP(C++)

이야기prog 2025. 4. 1. 21:03

client

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

#include <WinSock2.h>
#include <MSWSock.h>
#include <WS2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
int main()
{
	//윈도우 소켓 초기화
	// 관련 정보가 wsaData에 채워짐
	WSADATA wsaData;
	if (::WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
		return 0;

	// socket : address_family:(ipv4, ipv6...), type(tcp, udp), protocol / return: descriptor
	SOCKET clientSocket = ::socket(AF_INET, SOCK_STREAM, 0);

	if (clientSocket == INVALID_SOCKET) {
		int32 errCode = ::WSAGetLastError();
		cout << "erroCode: " << errCode << endl;
		return 0;
	}

	//연결할 목적지는?
	SOCKADDR_IN serverAddr; // ipv4
	::memset(&serverAddr, 0, sizeof(serverAddr));
	serverAddr.sin_family = AF_INET;
	::inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr); // internet presentation to network
	serverAddr.sin_port = ::htons(7777); // host to network short = big_endian으로 변환해줌

	if (::connect(clientSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
		int32 errCode = ::WSAGetLastError();
		cout << "erroCode: " << errCode << endl;
		return 0;
	}

	//========================
	// 연결 성공! 데이터 송수신 가능

	cout << "Connected to Server" << endl;

	while (true) {

		//TODO
		char sendBuffer[100] = "Hello, World!";

		for (int i = 0; i < 10; ++i) {
			int32 resultCode = ::send(clientSocket, sendBuffer, sizeof(sendBuffer), 0);
			if (resultCode == SOCKET_ERROR) {
				int32 errCode = ::WSAGetLastError();
				cout << "erroCode: " << errCode << endl;
				return 0;
			}

			cout << "Send Data! Len: " << sizeof(sendBuffer) << endl;

		}

		char recvBuffer[1000];

		int32 recvSize = ::recv(clientSocket, recvBuffer, sizeof(recvBuffer), 0);
		if (recvSize <= 0) {
			int32 errCode = ::WSAGetLastError();
			cout << "erroCode: " << errCode << endl;
			return 0;
		}

		cout << "Receive Data! Len: " << recvSize << endl;
		//this_thread::sleep_for(1s);
	}


	::closesocket(clientSocket); // 소켓 리소스 반환
	::WSACleanup(); // 윈속 종료
}

 

Server

 

#include "pch.h"
#include <thread>
#include <atomic>
#include <mutex>
#include <future>
#include "CorePch.h"
#include "ThreadManager.h"
#include "RefCounting.h"
#include "Memory.h"
#include "TypeCast.h"

#include <WinSock2.h>
#include <MSWSock.h>
#include <WS2tcpip.h>
#pragma comment(lib, "ws2_32.lib")


int main() {
	//윈도우 소켓 초기화
// 관련 정보가 wsaData에 채워짐
	WSADATA wsaData;
	if (::WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
		return 0;

	// socket : address_family:(ipv4, ipv6...), type(tcp, udp), protocol / return: descriptor
	SOCKET listenSocket = ::socket(AF_INET, SOCK_STREAM, 0);

	if (listenSocket == INVALID_SOCKET) {
		int32 errCode = ::WSAGetLastError();
		cout << "erroCode: " << errCode << endl;
		return 0;
	}

	//연결할 목적지는?
	SOCKADDR_IN serverAddr; // ipv4
	::memset(&serverAddr, 0, sizeof(serverAddr));
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_addr.s_addr = ::htonl(INADDR_ANY); // 알아서 세팅해줌 유동적으로 (127.0.0.1)도 되고, 자기 ip주소도 되고
	serverAddr.sin_port = ::htons(7777); // host to network short = big_endian으로 변환해줌

	if (::bind(listenSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
		int32 errCode = ::WSAGetLastError();
		cout << "erroCode: " << errCode << endl;
		return 0;
	}


	if (::listen(listenSocket, 10) == SOCKET_ERROR) {
		int32 errCode = ::WSAGetLastError();
		cout << "erroCode: " << errCode << endl;
		return 0;

	} // 대기열 10명까지

	// 연결 성공 
	while (true) {
		//TODO
			//연결할 목적지는?
		SOCKADDR_IN clientAddr; // ipv4
		::memset(&clientAddr, 0, sizeof(clientAddr));
		int32 addrLen = sizeof(clientAddr);

		SOCKET clientSocket = ::accept(listenSocket, (SOCKADDR*)&clientAddr, &addrLen);
		if (clientSocket == INVALID_SOCKET) {
			int32 errCode = ::WSAGetLastError();
			cout << "Accept erroCode: " << errCode << endl;
			return 0;

		}

		//손님 입장
		char ipAddress[16];
		::inet_ntop(AF_INET, &clientAddr.sin_addr, ipAddress, sizeof(ipAddress));
		cout << "Client Connected! IP = " << ipAddress << endl;

		//TODO
		while (true) {
			char recvBuffer[1000];

			this_thread::sleep_for(1s);
			int32 recvSize = ::recv(clientSocket, recvBuffer, sizeof(recvBuffer), 0);
			if (recvSize <= 0) {
				int32 errCode = ::WSAGetLastError();
				cout << "erroCode: " << errCode << endl;
				return 0;
			}

			cout << recvBuffer << endl;
			cout << "Receive Data! Len: " << recvSize << endl;

			int32 resultCode = ::send(clientSocket, recvBuffer, recvSize, 0);
			if (resultCode == SOCKET_ERROR) {
				int32 errCode = ::WSAGetLastError();
				cout << "erroCode: " << errCode << endl;
				return 0;
			}

			cout << "Send Data! Len: " << recvSize << endl;
		}
	}

	::WSACleanup(); // 윈속 종료
	return 0;
}

send, recv함수는 block함수로 실제 현업에서는 사용하기 힘들어보임. 

send함수는 kernel단에 send buffer에 데이터를 복사만 해도 성공

recv함수는 recv buffer에서 데이터를 복사해오면 성공

 

성공할 때까지 thread가 block상태이다.

'MMOServer' 카테고리의 다른 글

sockopt(C++)  (0) 2025.04.02
UDP(C++)  (0) 2025.04.01
SocketProgramming Basic(C++)  (0) 2025.04.01
ObjectPooling(C++)  (0) 2025.03.29
MemoryPool(C++)  (0) 2025.03.28