서버/네트워크

1. 소켓 프로그래밍

광란의슈가슈가룬 2024. 8. 29. 09:08

드디어 뭔가 통신같아 보이는 파트로 넘어왔다. 바로 코드부터 살펴보자.

 

DummyClient.cpp

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

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

int main()
{
	// 윈속 라이브러리 초기화 (ws2_32 라이브러리 초기화)
	// 관련 정보가 wsaData에 채워짐
	WSAData wsaData;
	if (::WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
		return 0;

	// af : 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) // 실패
	{
		int32 errCode = ::WSAGetLastError();
		cout << "Socket ErrorCode : " << errCode << endl;

		return 0;
	}

	// 연결할 목적지 (IP주소 + Port)
	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");
	::inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr);
	serverAddr.sin_port = ::htons(7777); // 엔디안 이슈, 네트워크는 주로 빅 엔디안

	if (::connect(clientSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)
	{
		int32 errCode = ::WSAGetLastError();
		cout << "Connect ErrorCode : " << errCode << endl;

		return 0;
	}

	//----------------------------------
	//	연결 성공, 데이터 송수신 가능

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

	while (true)
	{
		// TODO

		this_thread::sleep_for(1s);
	}

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

	// 소켓 리소스 반환
	::closesocket(clientSocket);

	// 윈속 종료, WSAStartup이 호출된 수만큼 실행해줘야 함
	::WSACleanup();
}

임시로 만든 서버와의 통신을 위한 클라이언트의 코드이다. 클라이언트가 해야할 일은 통신하고자하는 서버의 주소와 포트를 알고 연결 요청을 보내는 것이다. 물론 프로토콜 등을 고려해야 하지만 큰 흐름은 이렇다.

 

Server.cpp

#include "pch.h"
#include "CorePch.h"
#include <Windows.h>
#include "ThreadManager.h"

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

int main()
{
	// 윈속 라이브러리 초기화 (ws2_32 라이브러리 초기화)
	// 관련 정보가 wsaData에 채워짐
	WSAData wsaData;
	if (::WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
		return 0;

	// af : Address Family (AF_INET = IPv4, AF_INET6 = IPv6)
	// type : TCP(SOCK_STREAM) vs UDP(SOCK_DGRAM)
	// protocol : 0 (알아서 골라줌)
	// return : descriptor
	SOCKET listenSocket = ::socket(AF_INET, SOCK_STREAM, 0);
	if (listenSocket == INVALID_SOCKET) // 실패
	{
		int32 errCode = ::WSAGetLastError();
		cout << "Socket ErrorCode : " << errCode << endl;

		return 0;
	}

	// 나의 주소 (IP주소 + Port)
	SOCKADDR_IN serverAddr; // IPv4
	::memset(&serverAddr, 0, sizeof(serverAddr));
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_addr.s_addr = ::htonl(INADDR_ANY); // 알아서 해라
	serverAddr.sin_port = ::htons(7777);

	// 소켓과 서버 주소 연동
	if (::bind(listenSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)
	{
		int32 errCode = ::WSAGetLastError();
		cout << "Bind ErrorCode : " << errCode << endl;

		return 0;
	}

	// 연결 요청 받기 시작
	if (::listen(listenSocket, 10) == SOCKET_ERROR)
	{
		int32 errCode = ::WSAGetLastError();
		cout << "Listen ErrorCode : " << errCode << endl;

		return 0;
	}

	//-------------------------------
	
	while (true)
	{
		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 ErrorCode : " << errCode << endl;

			return 0;
		}

		// 클라이언트 접속 완료
		char ipAddress[16];
		::inet_ntop(AF_INET, &clientAddr.sin_addr, ipAddress, sizeof(ipAddress));
		cout << "Client Connected! IP : " << ipAddress << endl;

		//TODO
	}

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


	// 윈속 종료, WSAStartup이 호출된 수만큼 실행해줘야 함
	::WSACleanup();
}

서버는 먼저 자신의 주소와 소켓을 바인드 하고 클라이언트의 연결 요청을 받을 준비를 한 후 요청을 받기 시작한다. 

 

실행 결과

정상적으로 동작하는 것을 볼 수 있다.

 

굉장히 많은 처음보는 함수들이 등장한다. 하지만 분야 특성상 함수단위로 이해할 필요는 없고 전체적인 흐름만 이해하면 된다고 한다. 만약 헷갈리거나 모르는 함수들이 나타나면 마이크로소프트 공식 문서를 활용하자.

'서버 > 네트워크' 카테고리의 다른 글

6. Select 모델  (0) 2024.09.05
5. 논블로킹(Non-Blocking) 소켓  (2) 2024.09.03
4. 소켓 옵션  (3) 2024.09.01
3. UDP 서버  (2) 2024.08.30
2. TCP 서버  (0) 2024.08.29