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)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

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

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
GameChoi

Choi Programming

[SEVER] Non-blocking Socket
Create Game/[Window API] Game Client & Game Server

[SEVER] Non-blocking Socket

2023. 1. 11. 20:02

1. Blocking Socket

1.1 Blocking

 - accept, connect, recv, send

   - 대부분 소켓 관련 함수들은 호출 스레드를 블로킹 상태로 만듦
     - 블로킹 상태: 현재 스레드가 더 이상 코드를 진행하지 않고 block 상태로 멈춰 있는 상태

 1.2 Blocking 상태가 안 좋은 이유

 - 서버 1개와 연결된 클라이언트 수는 10개

   - 서버는 모든 클라이언트 패킷을 번갈아 가면서 받아야 함

     - 그러나 하나의 클라이언트에서 보내기만 하고 클라이언트가 종료가 된다면 서버는 블로킹 상태 유지

1.3 Blocking 상태를 사용하지 않는 방법

 - 함수 호출에 필요한 소켓을 논블로킹 상태로 변환

   - 이 소켓이 호출되고 클라이언트와 소통이 없으면 에러 코드를 반환 및 다음 클라이언트로 넘어감

 

2. Non-blocking Socket

2.1 Non-blocking Server

 - 기존 TCP서버를 이용하여 수정

 - https://choiprogramming.tistory.com/101

 

[SEVER] TCP Server

1. TCP 1.1 TCP의 의미 - 인터넷상에서 데이터를 메세지의 형태로 보내기 위해 IP를 함께 사용하는 프로토콜 1.2 특징 - 연결 지향 방식 - 3-way handshaking과정을 통해 연결 설정 및 4-way handshaking을 통해

choiprogramming.tistory.com

2.2 Non-blocking Socket

 - 소켓을 논블로킹 상태로 만들기

   - ioctlsocket 함수 사용 (Input / Output ConTroL Socket)

     - int ioctlsocket(SOCKET sock, long cmd, u_long* argp)

       - sock: 논블로킹 모드로 설정할 소켓을 의미

       - cmd: 소켓에 대해 수행할 동작을 의미하는 커맨드

         - FIONBIO

       - argp: cmd가 수행할 동작에 대한 판별 값

         - 0: 블로킹 상태

         - 0이 아닌 다른 값: 논 블로킹 상태

int main()
{
	// Init WSA
	// Socket Create
	// Server IP/HOST
    
	u_long NonBlockingMode = 1;
	if (::ioctlsocket(listenSocket, FIONBIO, &NonBlockingMode) == INVALID_SOCKET) return 0;

	// BIND
	// LISTEN
}

2.3 Accept

 - 논블로킹 소켓을 만든 상태

   - 클라이언트가 연결할 때까지 대기를 하고 있지만 논블로킹 상태이므로 멈춰있지 않음

     - 클라이언트의 접속이 없지만 블로킹을 해야하는데 논블로킹 상태

       - WSAEWOULDBLOCK: 연결요청을 받지 못했으므로 처음부터 다시하라는 의미

         - 오류는 아니므로 서버가 종료되지 않음

int main()
{
	// Init WSA
	// Socket Create
	// Server IP/HOST
	// Non-Blocking Socket
	// BIND
	// LISTEN
	while (true)
	{
		SOCKADDR_IN clientAddr;
		::memset(&serverAddr, 0, sizeof(serverAddr));
		int32 addrLength = sizeof(clientAddr);

		SOCKET clientSocket = ::accept(listenSocket,
						reinterpret_cast<SOCKADDR*>(&clientAddr), 
						&addrLength);
		if (clientSocket == INVALID_SOCKET)
		{
			// 접속 요청을 한 소켓이 없음
			if (::WSAGetLastError() == WSAEWOULDBLOCK) continue; // 문제가 되는 상황X
			
		}
	}
	// Close WSA
}

2.4 Recv & Send

 - Accept와 마찬가지로 논블로킹 상태

   - recv: 클라이언트가 보낸 값이 없음 (데이터를 아직 못받음)

   - send: 전송할 버퍼 공간이 없음 (데이터 초과?)

int main()
{
	// Init WSA
	// Socket Create
	// Server IP/HOST
	// Non-Blocking Socket
	// BIND
	// LISTEN
	while (true)
	{
		// 클라와 서버의 접속 완료
        while (true)
		{
			char recvBuffer[MAX_BUFFER];
			int32 recvLength = ::recv(clientSocket, recvBuffer, sizeof(recvBuffer), 0);
			if (recvLength == INVALID_SOCKET)
			{
				// 클라이언트가 보낸 값이 없음 - 데이터를 아직 못받음
				if (::WSAGetLastError() == WSAEWOULDBLOCK) continue; // 문제가 되는 상황X

				// TODO - 다른 에러 확인
			}
			cout << recvBuffer << endl;
		}
	}
	// Close WSA
}

3. Non-blocking Client

int main()
{
	// WSA 생성
	WSADATA Init;
	if (::WSAStartup(MAKEWORD(2, 2), &Init) != 0) return 0;

	// 소켓 생성
	SOCKET clientSocket = ::socket(AF_INET, SOCK_STREAM, 0);
	if (clientSocket == INVALID_SOCKET) return 0;

	// 서버 주소 및 포트 생성
	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);
	
	// 논블로킹 소켓 생성
	u_long NonBlockingMode = 1;
	if (::ioctlsocket(clientSocket, FIONBIO, &NonBlockingMode) == INVALID_SOCKET) return 0;

	// 서버와의 통신
	while (true)
	{
		// 서버와의 연결
		if (::connect(clientSocket, reinterpret_cast<SOCKADDR*>(&serverAddr), sizeof(serverAddr)) == SOCKET_ERROR)
		{
			// 연결할 서버가 없음
			if (::WSAGetLastError() == WSAEWOULDBLOCK) continue; // 문제가 되는 상황X
			if (::WSAGetLastError() == WSAEISCONN) break; // 이미 연결된 상태
		}
	}

	// 서버 통신
	while (true)
	{
		char sendBuffer[MAX_BUFFER] = "TEST SERVER";
		// 서버에게 메세지를 보냄
		int32 sendLength = ::send(clientSocket, sendBuffer, sizeof(sendBuffer), 0);
		if (sendLength <= SOCKET_ERROR)
		{
			// 공간이 부족하거나 보낼 수 없는 경우
			if (::WSAGetLastError() == WSAEWOULDBLOCK) continue; // 문제가 되는 상황X
		}

		this_thread::sleep_for(1s);
	}
}
저작자표시 (새창열림)

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

[SERVER] WSAEvent Select  (0) 2023.01.13
[SERVER] Select  (1) 2023.01.12
[SEVER] UDP Server  (0) 2023.01.10
[SEVER] TCP Server  (0) 2023.01.10
[SERVER] Memory Order  (0) 2023.01.05
    'Create Game/[Window API] Game Client & Game Server' 카테고리의 다른 글
    • [SERVER] WSAEvent Select
    • [SERVER] Select
    • [SEVER] UDP Server
    • [SEVER] TCP Server
    GameChoi
    GameChoi

    티스토리툴바