반응형
  • 티스토리 홈
  • 프로필사진
    묭묭.cpp
  • 방명록
  • 공지사항
  • 태그
  • 블로그 관리
  • 글 작성
묭묭.cpp
  • 프로필사진
    묭묭.cpp
    • 분류 전체보기 (103)
      • 데이터베이스 (2)
      • 포트폴리오 (25)
      • 윈도우 인터널즈 (20)
      • 네트워크 (4)
      • IOCP 게임서버 (11)
      • C (2)
      • 디스어셈블리 디버깅 (1)
      • WindowsAPI (11)
      • 학원 강의 정리 모음 (20)
      • 운영체제 (5)
  • 방문자 수
    • 전체:
    • 오늘:
    • 어제:
  • 최근 댓글
      등록된 댓글이 없습니다.
    • 최근 공지
        등록된 공지가 없습니다.
      # Home
      # 공지사항
      #
      # 태그
      # 검색결과
      # 방명록
      • IOCP 실습 2 Echo 서버 코드 분리 + 구조체 변수 이동
        2023년 08월 28일
        • 묭묭.cpp
        • 작성자
        • 2023.08.28.:52

        지난 시간에 실습한 IOCP Echo 서버의 2단계 실습이다.

         

        #출처 https://www.youtube.com/watch?v=RMRsvll7hrM

         

        먼저 2단계에서 진행할 작업을 정리하고 진행하도록 하겠다.

         

        1. 2단계에서 작업할 내용

        1. 선언부와 IOCP Class의 코드를 다른 파일로 분리한다.
        2. stOverlappedEx 구조체의 버퍼 정보를 stClientInfo 구조체로 옮긴다.

        1번 작업은 모든 코드가 한 파일에 존재하게 되면 코드의 양이 많아짐에 따라 복잡해지고 원하는 함수를 찾을 때 어려움이 발생한다. 따라서 실습 2단계에서는 구조체 정의, enum class 선언 등의 코드와 Server 코드를 분리하는 작업을 진행한다.

         

        2번 작업은 stOverlappedEx 구조체에 IO 버퍼 데이터가 포함되어 있고 너무 큰 버퍼의 용량을 지정하고 있으므로 불필요한 메모리의 낭비가 발생한다.

        ex) 비동기 IO 요청할 때마다 해당 구조체를 사용 (버퍼 데이터를 사용하지 않는 경우도 발생)

        따라서 버퍼 데이터를 Client 객체로 넘겨주고, SEND 버퍼와 RECV 버퍼를 분리하는 작업을 진행한다.

        2. 작업 내용

        1. 코드의 분리

        위 사진처럼 헤더파일 하나에 담겨있던 코드를

        코드 분리 작업을 진행하였다.

         

        • Define.h : 구조체의 선언 등의 데이터 구조를 선언하는 부분만을 담당할 헤더파일을 생성
        • IOCompletionPort.h : Server 프로그램의 전반적인 코드
        • pch.h : 미리 컴파일된 헤더

        1번 작업은 단순히 선언부와 프로그램 코드를 분리하는 작업으로 큰 어려움을 겪진 않았다.

        추가로 pch.h (미리 컴파일된 헤더)를 추가하여 라이브러리 정의 코드의 중복을 없애고 공통적으로 사용될 변수나 라이브러리를 이곳에 선언할 수 있도록 만들었다.

         

        2. stOverlappedEx의 버퍼 데이터를 stClientInfo로 이동

        struct stOverlappedEx
        {
        	WSAOVERLAPPED	        m_wsaOverlapped;
        	SOCKET			m_socketClient;
        	WSABUF			m_wsaBuf;
        	IOOperation		m_eOperation;
        };
        struct stClientInfo
        {
        	SOCKET			m_socketClient;
        	stOverlappedEx	        m_stRecvOverlappedEx;
        	stOverlappedEx	        m_stSendOverlappedEx;
        
        	char			m_recvBuf[MAX_SOCKBUF]; // 데이터 버퍼
        	char			m_sendBuf[MAX_SOCKBUF]; // 데이터 버퍼
        
        	stClientInfo()
        	{
        		// 메모리 영역을 0X00으로 채우는 매크로 : memset과 동일
        		ZeroMemory(&m_stRecvOverlappedEx, sizeof(stOverlappedEx));
        		ZeroMemory(&m_stSendOverlappedEx, sizeof(stOverlappedEx));
        		m_socketClient = INVALID_SOCKET;
        	}
        };
        • stOverlappedEx 구조체에 있던 m_szBuf를 삭제
        • stClientInfo 구조체에 RECV 버퍼와 SEND 버퍼 데이터 추가

        단순히 버퍼 데이터를 저장하는 위치를 변경하였다. 이로써 비동기 IO 작업(SEND, RECV)에서 항상 호출되던 stOverlappedEx 구조체가 아닌 stClientInfo 구조체로 버퍼 데이터를 옮기는 작업을 진행하였다.

         

        그런데 여기서?

        비동기 IO 작업은 SEND와 RECV 작업만 진행하는데 어디서 메모리 낭비가 발생하는지 의문을 갖게 되었다.

        ACCEPT 작업은 Blocking 작업이고 OVERLAPPED 구조체를 전달하지 않는데도 말이다.

        혹시 몰라서 ACCEPT 함수 뒷편에 Blocking 확인 코드를 넣고 테스트 해보았는데 해당 부분에서 메모리 낭비가 발생하지는 않다는 것은 확신할 수 있게 되었다.

        다음 확인 작업으로 어디서 OVERLAPPED 구조체가 사용되는지 코드 레벨에서 분석해보았다.

        int nRet = WSASend(pClientInfo->m_socketClient,
        			&(pClientInfo->m_stSendOverlappedEx.m_wsaBuf),
        			1,
        			&dwRecvNumBytes,
        			0,
        			(LPWSAOVERLAPPED) & (pClientInfo->m_stSendOverlappedEx),
        			NULL);
        int nRet = WSARecv(pClientInfo->m_socketClient,
        			&(pClientInfo->m_stRecvOverlappedEx.m_wsaBuf),
        			1,
        			&dwRecvNumBytes,
        			&dwFlag,
        			(LPWSAOVERLAPPED) & (pClientInfo->m_stRecvOverlappedEx),
        			NULL);

        다음과 같이 IOCP 오브젝트에 SEND와 RECV 작업을 예약할 때 stOverlappedEx 구조체의 포인터 변수가 전달되는 것을 알 수 있었다.

        그리고 해당 작업에서 IOCP 핸들에 작업을 요청하고 이 작업이 완료되면  IO Completion Queue에 완료정보를 밀어넣게 되는데

        IO Completion Queue의 구조를 살펴보면 pOverlapped 구조체의 포인터 변수가 들어가있다는 것을 알 수 있다.

        pOverlapped를 참조하여 작업을 할 때 사용하지도 않는 데이터 버퍼가 들어간다면 더 큰 메모리를 차지하게 되므로 메모리 낭비가 발생한다는 추측을 하였다.

         

        WSAOVERLAPPED 구조체를 확장하였을 때 데이터를 포함하는 경우 어떤 이유에서 메모리 낭비가 발생하는지 더 확실한 답을 구하기 위해 검색과 ChatGPT를 활용하여 정보를 구해보았다.

         

        1. 구조체 크기의 증가 : OVERLAPPED 구조체는 비동기 I/O 작업을 추적하는데 필요한 데이터와 포인터를 포함한다. 따라서 불필요하게 큰 데이터(버퍼 데이터)를 포함하면 구조체가 크게 증가함으로 메모리를 불필요하게 낭비하게 된다.
        2. 메모리 오버헤드 발생 : 버퍼 데이터를 추가함으로 완료 관리 데이터와 실제 데이터가 혼합되어 메모리 관리에 대한 오버헤드가 발생할 수 있다. * 오버헤드란? 필요하지 않은 추가 메모리
        3. 응용 프로그램 복잡성 : 데이터를 추가함으로써 추가적인 로직과 작업이 필요할 수 있으므로 코드가 더 어려워질 수 있다.

        위와 같은 이유로 OVERLAPPED 구조체와 실제 데이터를 분리하는 것이 일반적으로 더 효율적인 방법이다.

        OVERLAPPED 구조체로 비동기 I/O를 추적하고 작업이 완료되었을 때 데이터를 버퍼에서 가져오는 방식으로 설계하면 메모리 낭비를 최소화하고 코드를 더 쉽게 관리할 수 있다.

         

        즉, OVERLAPPED 구조체와 추가적인 데이터는 분리하자!

         

        여기까지... OVERLAPPED 구조체와 버퍼 데이터를 분리하는 작업을 수행하였고

        후처리로 일전에 stOverlappedEx 구조체에서 버퍼를 사용하는 부분을 stClientEx 구조체에서 각 목적에 맞는 (SEND와 RECV) 버퍼를 사용하도록 코드를 수정하면 된다.

         

        일단 구조체 코드를 변경하게 되면 일전에 사용하던 코드에서 오류 메시지를 출력하게 된다.

        해당 부분을 찾아서 적절하게 수정하면 완료이다.

         

        코드는 워낙 간단하기 때문에 따로 첨부하지는 않겠다.

         

        중간에 어디서 메모리 낭비가 나는지? 생각하면서 OVERLAPPED 구조체에 대한 이해를 쌓는데 큰 도움이 된 것 같다.

        이번 실습에서 이해한 내용을 간단히 정리해보면 OVERLAPPED 구조체는 비동기 I/O 작업을 추적하는데 필요한 구조체이기 때문에 불필요한 데이터는 분리하는 것이 좋다! 라는 것이다.

         

        나중에 보면 이런 하수같은 생각도 했었구나라고 떠올릴 수 있도록 실력을 착실히 쌓아나갈 수 있었으면 좋겠다.

         

        IOCP 2단계 실습 깃허브 링크 첨부하고 2단계 실습 포스팅은 마무리하도록 하겠다.

        https://github.com/MyungHyun-Ahn/Server-Programming-Study/tree/main/IOCP_STUDY/IOCP_02

         

         

        반응형

        'IOCP 게임서버' 카테고리의 다른 글

        IOCP 실습 6 Echo 서버 - 1-Send 방식 (Queue 방식 구현)  (0) 2023.08.31
        IOCP 실습 5 Echo 서버 - 1-Send 방식과 N-Send 방식 (SendBuffer 구현)  (0) 2023.08.30
        IOCP 실습 4 Echo 서버 - 네트워크 / 로직 처리 각각의 쓰레드로 분리  (2) 2023.08.30
        IOCP 실습 3 Echo 서버 - 역할에 따라 코드 분리 + 연결, 끊어짐, 데이터 받음을 애플리케이션에 전달  (0) 2023.08.29
        IOCP 실습 1 Echo Server 만들기  (0) 2023.08.28
        다음글
        다음 글이 없습니다.
        이전글
        이전 글이 없습니다.
        댓글
      조회된 결과가 없습니다.
      스킨 업데이트 안내
      현재 이용하고 계신 스킨의 버전보다 더 높은 최신 버전이 감지 되었습니다. 최신버전 스킨 파일을 다운로드 받을 수 있는 페이지로 이동하시겠습니까?
      ("아니오" 를 선택할 시 30일 동안 최신 버전이 감지되어도 모달 창이 표시되지 않습니다.)
      목차
      표시할 목차가 없습니다.
        • 안녕하세요
        • 감사해요
        • 잘있어요

        티스토리툴바