이번에는 간단하게 소켓 옵션을 설정하는 방법에 대해 알아보자.
소켓을 만들 때 기본적으로 커널에서 샌드, 리시브 버퍼(송수신 버퍼)가 만들어진다. 이 버퍼도 크기를 변경하는 등 프로그래머가 옵션을 설정할 수 있다.
::setsockopt();
::getsockopt();
이 두 함수를 통해 옵션을 설정하고 가져올 수 있다. 자세한 내용은 마이크로소프트 공식문서에 잘 나와있다.
https://learn.microsoft.com/ko-kr/windows/win32/api/winsock2/nf-winsock2-setsockopt
간단하게 몇 가지만 알아보았는데 만약 필요한 것이 있다면 문서를 참고해서 사용하면 된다.
#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;
// UDP
SOCKET serverSocket = ::socket(AF_INET, SOCK_DGRAM, 0);
if (serverSocket == INVALID_SOCKET)
{
HandleError("Socket");
return 0;
}
// 옵션 해석하고 처리할 주체? level
// 소켓 코드 -> SOL_SOCKET
// IPv4 -> IPPROTO_IP
// TCP 프로토콜 -> IPPROTO_TCP
// SO_KEEPALIVE = 주기적으로 연결 상태 확인 여부 (TCP Only)
// 상대방이 갑자기 연결을 끊을 수 있음
// 주기적으로 TCP 프로토콜 연결상태 확인 -> 끊어짐 감지
bool enable = true;
::setsockopt(serverSocket, SOL_SOCKET, SO_KEEPALIVE, (char*)&enable, sizeof(enable));
// SO_LINGER = 지연하다
// send -> closesocket 할 경우 send 버퍼에 데이터가 남음
// 송신 버퍼에 있는 데이터를 보낼 것인지 여부
// onoff = 0이면 closesocket()이 바로 리턴, 0이 아니면 linger초 만큼 대기(default 0)
// linger = 대기시간
LINGER linger;
linger.l_onoff = 1;
linger.l_linger = 5;
::setsockopt(serverSocket, SOL_SOCKET, SO_LINGER, (char*)&linger, sizeof(linger));
// 일방적으로 closesocket를 하는 것이 아니라
// Half-Close, 즉 반만 닫음으로써 미리 알려줌
// SD_SEND : send 막음
// SD_RECEIVE : recv 막음
// SD_BOTH : 둘 다 막음
//::shutdown(serverSocket, SD_SEND); // 더 이상 보낼 것이 없다!
// 소켓 리소스 반환
//::closesocket(serverSocket);
//SO_SNDBUF = 송신 버퍼 크기
//SO_RCVBUF = 수신 버퍼 크기
int32 sendBufferSize;
int32 optionLen = sizeof(sendBufferSize);
::getsockopt(serverSocket, SOL_SOCKET, SO_SNDBUF, (char*)&sendBufferSize, &optionLen);
cout << "송신 버퍼 크기 : " << sendBufferSize << endl;
int32 recvBufferSize;
optionLen = sizeof(recvBufferSize);
::getsockopt(serverSocket, SOL_SOCKET, SO_RCVBUF, (char*)&recvBufferSize, &optionLen);
cout << "수신 버퍼 크기 : " << recvBufferSize << endl;
// SO_REUSEADDR
// IP주소 및 port 재사용
{
bool enable = true;
::setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&enable, sizeof(enable));
}
// IPPROTO_TCP
// TCP_NODELAY = Nagle 네이글 알고리즘 작동 여부
// 데이터가 충분히 크면 보내고, 그렇지 않으면 데이터가 쌓일 때까지 대기
// 장점 : 작은 패킷이 불필요하게 많이 생성되는 것 방지
// 단점 : 반응 시간 손해
// 일반적으로 게임서버의 경우 꺼줌(반응 시간이 더 중요!)
{
bool enable = true; // true일 때 끄는 것!!
::setsockopt(serverSocket, IPPROTO_TCP, TCP_NODELAY, (char*)&enable, sizeof(enable));
}
// 윈속 종료, WSAStartup이 호출된 수만큼 실행해줘야 함
::WSACleanup();
}
자주 사용되는 몇 가지 함수만 알아보았다. 주석으로 간단하게 설명해 놓았으므로 후술하진 않겠다. 이 외에 다른 많은 함수들이 있으니 필요할 경우 공식 문서를 참조하도록 하자.
'서버 > 네트워크' 카테고리의 다른 글
6. Select 모델 (0) | 2024.09.05 |
---|---|
5. 논블로킹(Non-Blocking) 소켓 (2) | 2024.09.03 |
3. UDP 서버 (2) | 2024.08.30 |
2. TCP 서버 (0) | 2024.08.29 |
1. 소켓 프로그래밍 (0) | 2024.08.29 |