GameChoi
Choi Programming
GameChoi
전체 방문자
오늘
어제
  • 분류 전체보기 (468)
    • C++ Algorithm & Study (184)
      • C++ & Algorithm Strategies (45)
      • Game Math & DirectX 11 (72)
      • Server + UE5 (29)
      • Lyra Clone Coding (37)
    • Create Game (284)
      • [Window API] Game Client & .. (55)
      • [DirectX] DirectX 2D & 3D (155)
      • [UE5] BLUEPRINT & C++ (74)
    • odds and ends (0)
      • English (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • Direct3D
  • core
  • Game Server
  • GAME Client
  • session
  • Direct11
  • c++
  • UE5
  • RPG Game
  • Destination Move Packet
  • Game Room
  • job queue
  • Network Worker
  • client
  • Player Move Packet
  • Algorithm Strategies
  • Other Character
  • server
  • protobuf
  • Player State

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
GameChoi

Choi Programming

[SERVER] Overlapped I/O
Create Game/[Window API] Game Client & Game Server

[SERVER] Overlapped I/O

2023. 1. 14. 19:26

1. Overlapped I/O

1.1 Overlapped I/O 의미

 - 하나의 스레드에서 둘 이상의 패킷 데이터를 통신용 소켓에 송수신

   - 여러 개의 소켓에 입출력이 중첩된 상황

1.2 Non-blocking Code 수정

https://choiprogramming.tistory.com/106

 

[SEVER] Non-blocking Socket

1. Blocking Socket 1.1 Blocking - accept, connect, recv, send - 대부분 소켓 관련 함수들은 호출 스레드를 블로킹 상태로 만듦 - 블로킹 상태: 현재 스레드가 더 이상 코드를 진행하지 않고 block 상태로 멈춰 있

choiprogramming.tistory.com

1.3 Overlapped I/O

 - overlapped 구조체 생성

struct Session
{
	SOCKET socket = INVALID_SOCKET;
	char recvBuffer[MAX_BUFFER] = {};
	WSAOVERLAPPED overlapped;
};

 - Base Code

int main()
{
	// Init WSA, Socket Create, Server IP/HOST
	// Non-Blocking Socket, BIND, LISTEN
	while (true)
	{
		// accept
	}
	// Close WSA
}

 - 이벤트 핸들 오브젝트의 시그널 상태를 Overlapped 구조체에 알릴 이벤트 생성
   - 소켓의 입출력 작업이 완료되면 OS는 애플리케이션이 등록한 이벤트 객체의 신호 상태를 바꿈

   - 애플리케이션은 이를 바탕으로 이벤트 객체를 관찰함으로써 작업 완료를 감지
   - OVERLAPPED 구조체에 Event 객체를 등록
     - 비동기 입출력 함수에서 이 구조체 등록된 이벤트를 통해 현재 완료된 입출력의 상태 정보를 감지
 - 소켓의 버퍼 정보를 담고있는 구조체 (wsabuf)
   - 비동기 입출력 함수인 WSASend, WSARecv는 이 구조체에 들어있는 버퍼의 정보를 사용한다.
   - WSABUF구조체에 전송할 버퍼의 종류와 사이즈를 넣어준다.

int main()
{
	// Init WSA, Socket Create, Server IP/HOST
	// Non-Blocking Socket, BIND, LISTEN
	while (true)
	{
		// accept
		{
			// 클라이언트 데이터 생성
			Session session = Session{ clientSocket };

			// 이벤트 핸들 오브젝트의 시그널 상태를 Overlapped 구조체에 알리는 이벤트 생성
			WSAEVENT hEvent = WSACreateEvent();

			// 현재 완료된 입출력의 상태 정보를 감지
			session.overlapped.hEvent = hEvent;
			while (true)
			{
				// WSABUF구조체에 전송할 버퍼의 종류와 사이즈를 넣음
				WSABUF wsaBuf;
				wsaBuf.len = MAX_BUFFER; // 패킷 사이즈 설정
				wsaBuf.buf = session.recvBuffer; // 패킷 종류 설정 

				// 데이터 저장할 변수 추가
				DWORD dwRecvBytes = 0;
				DWORD dwFlag = 0;
			}
		}
		// Close WSA
	}

 - 접속된 상대방의 소켓으로부터 전송된 패킷 데이터를 받음

   - socket: 접속된 소켓 지정

   - lpBuffers: WSABUF 구조체 버퍼 포인터

   - dwBufferCount: WSABUF 버퍼 카운터

   - lpNumberOfBytesRecvd: Recv 완료 후 함수의 호출로 읽어낸 데이터의 바이트 수

   - lpFlags: 입출력 Flag 설정, 이 플래그를 통해 WSARecv가 구체적으로 동작하게 될 작업 명시

   - LPWSAOVERLAPPED: OVERLAPPED 구조체 포인터

   - LPWSAOVERLAPPED_COMPLETION_ROUTINE: 컴플리트 루틴 (TODO)

int WSARecv (SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
	LPDWORD lpNumberOfBytesRecvd,
	LPDWORD lpFlags, LPWSAOVERLAPPED lpOverlapped, 
	LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionROUTINE);

   - 에러 코드가 WSA_IO_PENDING이면 중첩 연산이 성공적으로 진행된 것

     - 모든 값 통과시 출력

int main()
{
	// Init WSA, Socket Create, Server IP/HOST
	// Non-Blocking Socket, BIND, LISTEN
	while (true)
	{
		// accept
				// 클라이언트 데이터 생성, 이벤트 생성
		while (true)
		{
			// 현재 완료된 입출력의 상태 정보를 감지 및 전송할 버퍼의 종류와 사이즈 입력

			// 접속된 상대방의 소켓으로부터 전송된 패킷 데이터를 받음
			if (WSARecv(session.socket, &wsaBuf, 1, &dwRecvBytes, &dwFlag, &session.overlapped, nullptr) == SOCKET_ERROR)
			{
				// 에러 코드가 WSA_IO_PENDING이면 중첩 연산이 성공적으로 진행된 것
				if (WSAGetLastError() == WSA_IO_PENDING)
				{

				}
				else continue;
			}
			cout << session.recvBuffer << endl;
		}
	}
	// Close WSA
}

 - 이벤트 상태가 시그널 상태가 될때 까지 대기 및 에빈트 객체의 신호 상태를 감지

 - 오버랩 연산의 결과를 반환

   - lpcbTransfer: 실제로 송수신된 바이트의 개수를 받는 포인터

   - fWait

     - FALSE: WSA_IO_INCOMPLETE 에러 코드를 반환

     - TRUE: Overlapped I/O가 완료될 때까지 대기

   - lpdwFlags: 작업 완료 상태를 가진 플래그를 수신할 포인터

BOOL WSAGetOverlappedResult (
		SOCKET s, LPWSAOVERLAPPED lpOverlapped,
		LPDWORD lpcbTransfer, BOOL fWait,LPDWORD lpdwFlags
);

int main()
{
	// Init WSA, Socket Create, Server IP/HOST
	// Non-Blocking Socket, BIND, LISTEN
	while (true)
	{
		// accept
				// 클라이언트 데이터 생성, 이벤트 생성
		while (true)
		{
			// 현재 완료된 입출력의 상태 정보를 감지 및 전송할 버퍼의 종류와 사이즈 입력

			// 접속된 상대방의 소켓으로부터 전송된 패킷 데이터를 받음
			if (WSARecv(session.socket, &wsaBuf, 1, &dwRecvBytes, &dwFlag, &session.overlapped, nullptr) == SOCKET_ERROR)
			{
				// 에러 코드가 WSA_IO_PENDING이면 중첩 연산이 성공적으로 진행된 것
				if (WSAGetLastError() == WSA_IO_PENDING)
				{
					// 이벤트 상태가 시그널 상태가 될때 까지 대기 및 에빈트 객체의 신호 상태를 감지
					::WSAWaitForMultipleEvents(1, &hEvent, TRUE, WSA_INFINITE, FALSE);
					// 감지가 된다면 오버랩 연산의 결과를 반환
					::WSAGetOverlappedResult(session.socket, &session.overlapped, &dwRecvBytes, FALSE, &dwFlag);
				}
				else continue;
			}
			cout << session.recvBuffer << endl;
		}
	}
	// Close WSA
}

1.4 Overlapped I/O Callback

struct Session
{
	WSAOVERLAPPED overlapped;
	SOCKET socket = INVALID_SOCKET;
	char recvBuffer[MAX_BUFFER] = {};
};

 - WSARecv을 실행하고 완료가 된다면 RecvCompRoutine 함수 실행

   - 이때 PENDING상태이면 SleepEx를 사용하여 Alertable 상태 변경

     - I/O 연산이 완료되면 완료 루틴을 실행해야 하는데 이 완료 루틴이 실행되는 타이밍을 결정지을 수 있음

       - 완료 루틴을 실행하라고 알려주게 됨

if (WSARecv(session.socket, &wsaBuf, 1, &dwRecvBytes, &dwFlag, &session.overlapped, RecvCompRoutine) == SOCKET_ERROR)
{
    // 에러 코드가 WSA_IO_PENDING이면 중첩 연산이 성공적으로 진행된 것
    if (WSAGetLastError() == WSA_IO_PENDING)
    {
        SleepEx(INFINITE, true);
    }
    else continue;
}

 - RecvCompRoutine

   - WSARecv가 완료가 된다면 SleepEx로 부터 완료 루틴을 실행

     - Overlapped의 주소를 받아 세션을 생성한 후 출력

void CALLBACK RecvCompRoutine(DWORD dwError, DWORD szRecvBytes, LPWSAOVERLAPPED lpOverlapped, DWORD flags)
{
	Session* session = reinterpret_cast<Session*>(lpOverlapped);
	cout << session->recvBuffer << endl;
}

 

 

2. Client

https://choiprogramming.tistory.com/112

 

[SERVER] WSAEvent Select

1. WSAEventSelect (Windows Socket Async) 1.1 WSAEventSelect 의미 - 입출력 함수를 안전하게 호출할 수 있는 시점을 운영체제가 알려줌 - 단순한 입출력 방식보다 편리하게 여러개의 소켓을 처리 - 운영체제에

choiprogramming.tistory.com

 

저작자표시 (새창열림)

'Create Game > [Window API] Game Client & Game Server' 카테고리의 다른 글

[GameServer] 1. IOCP Server Core & Accept  (0) 2023.01.17
[SERVER] IOCP  (0) 2023.01.14
[SERVER] WSAEvent Select  (0) 2023.01.13
[SERVER] Select  (1) 2023.01.12
[SEVER] Non-blocking Socket  (1) 2023.01.11
    'Create Game/[Window API] Game Client & Game Server' 카테고리의 다른 글
    • [GameServer] 1. IOCP Server Core & Accept
    • [SERVER] IOCP
    • [SERVER] WSAEvent Select
    • [SERVER] Select
    GameChoi
    GameChoi

    티스토리툴바