논블로킹 소켓

Jaemyeong Lee·2024년 12월 5일
0

1. 서버 코드 분석

1-1. 소켓 초기화 및 설정

SocketUtils::Init();
  • 설명:
    • 네트워크 소켓 라이브러리를 초기화하는 함수입니다.
    • Windows에서는 WSAStartup()을 호출하여 소켓을 사용할 수 있도록 준비합니다.

SOCKET listenSocket = ::socket(AF_INET, SOCK_STREAM, 0);
if (listenSocket == INVALID_SOCKET)
    return 0;
  • 설명:
    • socket() 함수는 소켓을 생성합니다.
    • 매개변수:
      • AF_INET: IPv4 인터넷 프로토콜을 사용.
      • SOCK_STREAM: TCP 프로토콜 기반의 스트림 소켓.
      • 0: 기본 프로토콜(TCP)을 사용.
    • 반환값:
      • 성공 시 소켓 핸들을 반환.
      • 실패 시 INVALID_SOCKET 반환.
    • 오류 처리:
      • 소켓 생성 실패 시 프로그램을 종료합니다.

u_long on = 1;
if (::ioctlsocket(listenSocket, FIONBIO, &on) == INVALID_SOCKET)
    return 0;
  • 설명:
    • ioctlsocket 함수는 소켓의 속성을 설정합니다.
    • FIONBIO 플래그를 사용하면 소켓이 논블로킹 모드로 설정됩니다.
    • on = 1: 논블로킹 모드 활성화.
    • 반환값:
      • 성공 시 0 반환.
      • 실패 시 INVALID_SOCKET 반환.

SocketUtils::SetReuseAddress(listenSocket, true);
  • 설명:
    • 소켓 옵션 중 하나인 주소 재사용(Reuse Address)를 설정합니다.
    • 이전에 사용된 소켓 주소가 바로 재사용될 수 있도록 합니다.

if (SocketUtils::BindAnyAddress(listenSocket, 7777) == false)
    return 0;
  • 설명:
    • bind() 함수를 사용해 소켓을 특정 주소와 포트에 바인딩합니다.
    • 7777: 서버가 수신할 포트 번호입니다.
    • 반환값:
      • 성공 시 true.
      • 실패 시 프로그램을 종료.

if (SocketUtils::Listen(listenSocket, SOMAXCONN) == false)
    return 0;
  • 설명:
    • listen() 함수는 소켓을 수신 대기 상태로 설정합니다.
    • SOMAXCONN: 최대 대기 가능한 연결 요청 수를 설정.

1-2. 클라이언트 연결 처리

SOCKADDR_IN clientAddr;
int32 addrLen = sizeof(clientAddr);
  • 설명:
    • 클라이언트 주소 정보를 저장할 SOCKADDR_IN 구조체를 선언합니다.
    • addrLen은 클라이언트 주소 구조체의 크기를 설정합니다.

while (true)
{
    SOCKET clientSocket = ::accept(listenSocket, (SOCKADDR*)&clientAddr, &addrLen);
    if (clientSocket == INVALID_SOCKET)
    {
        if (::WSAGetLastError() == WSAEWOULDBLOCK)
            continue;
    }
    cout << "Client Connected!" << endl;
  • 설명:
    1. accept() 함수:
      • 클라이언트 연결 요청을 수락합니다.
      • 논블로킹 모드에서는 클라이언트가 없을 경우 INVALID_SOCKET을 반환합니다.
    2. WSAGetLastError():
      • 오류 코드가 WSAEWOULDBLOCK이면, 클라이언트가 없음을 의미합니다.
      • 계속 루프를 실행합니다.
    3. 연결이 성공하면 "Client Connected!" 메시지를 출력합니다.

1-3. 데이터 수신 처리

while (true)
{
    char recvBuffer[1000];
    int32 recvLen = ::recv(clientSocket, recvBuffer, sizeof(recvBuffer), 0);
    if (recvLen == SOCKET_ERROR)
    {
        if (::WSAGetLastError() == WSAEWOULDBLOCK)
            continue;

        break;
    }

    cout << "Recv Data = " << recvBuffer << endl;
    cout << "Recv Data len = " << recvLen << endl;
}
  • 설명:
    1. recv() 함수:
      • 데이터를 수신합니다.
      • 논블로킹 모드에서 수신할 데이터가 없으면 SOCKET_ERROR와 함께 WSAEWOULDBLOCK 오류 코드가 반환됩니다.
    2. 오류 처리:
      • WSAEWOULDBLOCK: 데이터가 아직 도착하지 않음을 의미하며, 계속 루프를 실행합니다.
      • 다른 오류 코드가 발생하면 루프를 종료합니다.
    3. 데이터 수신 성공 시:
      • 수신된 데이터를 출력합니다.

SocketUtils::Close(listenSocket);
  • 설명:
    • close() 함수로 소켓을 닫고 네트워크 리소스를 해제합니다.

2. 클라이언트 코드 분석

2-1. 소켓 생성 및 설정

SOCKET clientSocket = ::socket(AF_INET, SOCK_STREAM, 0);
if (clientSocket == INVALID_SOCKET)
    return 0;

u_long on = 1;
if (::ioctlsocket(clientSocket, FIONBIO, &on) == INVALID_SOCKET)
    return 0;
  • 설명:
    1. socket() 함수:
      • TCP 소켓을 생성합니다.
    2. ioctlsocket():
      • 소켓을 논블로킹 모드로 설정합니다.

2-2. 서버에 연결 요청

SOCKADDR_IN serverAddr;
::memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
::inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr);
serverAddr.sin_port = ::htons(7777);

while (true)
{
    if (::connect(clientSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)
    {
        if (::WSAGetLastError() == WSAEWOULDBLOCK)
            continue;

        if (::WSAGetLastError() == WSAEISCONN)
            break;
    }
}
  • 설명:
    1. connect() 함수:
      • 서버에 연결을 시도합니다.
      • 논블로킹 모드에서는 WSAEWOULDBLOCK 오류가 반환되면 연결 시도가 진행 중임을 의미합니다.
    2. WSAEISCONN:
      • 이미 연결이 완료된 상태를 나타냅니다.

2-3. 데이터 송신

while (true)
{
    char sendBuffer[100] = "Hello I am Client!";
    int32 sendLen = sizeof(sendBuffer);

    if (::send(clientSocket, sendBuffer, sendLen, 0) == SOCKET_ERROR)
    {
        if (::WSAGetLastError() == WSAEWOULDBLOCK)
            continue;

        cout << "Send Data ! Len = " << sendLen << endl;			
    }

    this_thread::sleep_for(1s);
}
  • 설명:
    1. send() 함수:
      • 데이터를 서버에 송신합니다.
      • 논블로킹 모드에서 버퍼가 가득 차 있으면 WSAEWOULDBLOCK 오류를 반환합니다.
    2. 송신 성공:
      • 송신된 데이터의 길이를 출력합니다.
    3. 1초 대기:
      • sleep_for(1s)를 사용해 1초마다 데이터를 송신합니다.

2-4. 소켓 종료

SocketUtils::Close(clientSocket);
  • 설명:
    • 소켓을 닫아 클라이언트의 네트워크 리소스를 해제합니다.

3. 요약 및 흐름

서버:

  1. 소켓 생성논블로킹 모드 설정바인딩수신 대기클라이언트 연결데이터 수신.

클라이언트:

  1. 소켓 생성논블로킹 모드 설정서버 연결데이터 송신.

profile
李家네_공부방

0개의 댓글