소켓 client, server를 직접 만들어보자.
윈도우 라이브러리를 이용한 방법이다.
DummyClient.cpp
#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))
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)
{
int32 errCode = ::WSAGetLastError();
cout << "Socket ErrorCode : " << errCode << endl;
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");
::inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr);
serverAddr.sin_port = ::htons(7777);
// host to network short(호스트에서 네트워크 방식 엔디언으로 바꾸겠다)
// Little-Endian vs Big-Endian
// ex) 0x12345678 4바이트 정수
// low [0x78][0x56][0x34][0x12] high > little
// low [0x12][0x34][0x56][0x78] hight > big = network표준
// 확인
// int16 num = 0x1234;
// int16 num2 = ::htons(num);
if (::connect(clientSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr)))
{
int32 errCode = ::WSAGetLastError();
cout << "Socket ErrorCode : " << errCode << endl;
return 0;
}
// ----------------------------
// 연결 성공! 이제부터 데이터 송수신 가능!
cout << "Connected to Server!" << endl;
while (true)
{
// TODO
this_thread::sleep_for(1s);
}
// ---------------------------
// 소켓 리소스 반환
::closesocket(clientSocket);
// 윈속 종료
::WSACleanup();
}
함수 각각을 알아보는 작업도 필요하지만 중요한 것은 큰 흐름을 아는 것이다.
client에서는 socket을 준비하고 목적지를 세팅한 뒤 connect한다.
GameServer.cpp
#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))
return 0;
// ad: 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;
}
// 나의 주소는?
SOCKADDR_IN serverAddr; // IPv4
::memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = ::htonl(INADDR_ANY); // <니가 알아서 해줘
// 위 값 특정하면 해당 주소로만 연결됨.
// 만약 네트워크 카드가 여러 개 있어 주소를 여러 개 가지고 있고
// INADDR_ANY하면 유동적으로 주소를 골라서 연결함.
serverAddr.sin_port = ::htons(7777);
// 안내원 폰 개통! 식당의 대표 번호
if (::bind(listenSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)
{
int32 errCode = ::WSAGetLastError();
cout << "Socket ErrorCode : " << errCode << endl;
return 0;
}
// 영업 시작!
// backlog : 대기열의 max count
if (::listen(listenSocket, 10) == SOCKET_ERROR)
{
int32 errCode = ::WSAGetLastError();
cout << "Socket 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 << "Socket 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
}
// ----------------------------
// 윈속 종료
::WSACleanup();
}
소켓 서버는 socket을 준비하고 bind 이용하여 socket을 세팅하고 listen으로 socket 연결을 받는다.
accept에서 대기하다가 client에서 연결이 오면 깨어나서 이후의 작업을 진행한다.
accept반환 값인 SOCKET을 통해 클라이언트와 통신할 수 있다.
1. Address Family 중, Ipv4, Ipv6를 의미하는 정의는 각각 무엇?
- Ipv4 : AF_INET, Ipv6 : AF_INET6
2. TCP, UDP를 의미하는 정의는 각각 무엇?
- Tcp : SOCK_STREAM, Udp : SOCK_DGRAM
3. 리틀 앤디안, 빅 앤디안 차이는?
- 리틀 앤디안 : 작은 단위 숫자가 큰 번지의 주소에 저장됨.
- 빅 앤디안 : 리틀 앤디안 반대
4. 클라이언트와 소켓 연결 후, 클라이언트와 통신하기 위해 필요한 값은?
- accept 반환 값인 SOCKET
참조 : [C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버 - 인프런 | 강의 (inflearn.com)
TCP vs UDP (0) | 2021.11.05 |
---|---|
TCP서버 실습 (0) | 2021.11.05 |
소켓 프로그래밍 기초 #1 (0) | 2021.11.03 |
TypeCast (0) | 2021.10.29 |
Object pool (0) | 2021.10.01 |
댓글 영역