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

        지난 시간에 이어 1-Send 방식을 다른 방법으로 구현해보는 실습을 진행해보도록 하겠다.

        Buffer를 이용한 방식을 이해했으므로 Queue를 사용하는 방식도 쉽게 구현할 수 있을 거 같아서 바로 진행해보려고 한다.

         

        #출처 https://www.youtube.com/watch?v=eLKJuJqBkHU&t=1s 

         

        1. 설계

        먼저 설계부터 글로 써놓고 구현을 하였다.

        1. SendData를 담을 클래스를 선언한다. (생성자에서 모든 세팅이 가능하다.)
        2. SendData의 포인터 변수를 가지는 Queue를 생성한다.
        3. Send가 호출되면 SendData에 값을 세팅하고 Queue에 넣는다.
        4. 5번 실습과 동일한 방법으로 client 루프를 돌며 전송 작업을 수행한다.

        위와 같이 설계하고 바로 프로그램 코드 작업에 들어갔다.

         

        2. 프로그램 구현

        위의 설계를 그대로 따라 구현하면 된다.

        1. SendData 클래스 선언. (생성자에서 모든 세팅 가능)
        2. Send가 호출되면 SendData를 담는 Queue에 SendData의 주소값을 넣는다. (락처리)
        3. Send 쓰레드에서 루프를 돌며 Send가 가능한지? Queue에 데이터가 있는지를 체크한다.
        4. Send가 가능하면 Send를 한다. (락처리)
        5. Send가 완료되면 Queue에서 Pop을 하고 SendData의 메모리를 할당해제한다. (락처리)

        락처리에 유의하여 다음과 같이 구현하면 된다.

        구현의 작업에서 그렇게 큰 어려움이 있지 않을 것 같았지만....

        테스트 클라이언트에서 패킷을 매우 빠르게 전송하면 서버가 터져버리는 문제가 발생하였다.

         

        바로 Queue의 front 함수를 호출하여 데이터를 꺼내서 할당해제하는 부분이었는데 데이터를 꺼내는 과정에서 데이터가 없어서 실행 도중 서버가 꺼져버린 것이었다.

        설계 상으로는 Send를 요청하면 무조건 Queue에 데이터가 1개 이상있고 Send를 완료처리할 때도 무조건 데이터가 1개 이상있어야 한다.

         

        나는 여기서 데이터가 왜 비어버릴까?를 고민해보았다.

        아마도 여러개의 쓰레드가 접근해서 Queue에서 데이터를 너무 빠르게 꺼내버린 거 아닐까? 라고 예상하고 코드를 분석해보았다.

        그런데 Queue의 데이터에 접근하는 부분에 모두 락처리를 하였는데 문제가 발생한 것이었다.

        조금 더 코드를 분석해본 결과 정말 어리석은 실수를 하고만 것이다.

        해당 에러의 발생 원인은 이러하다.

        1. Send의 완료처리를 하는 부분에서 락을 걸었다.
        2. 다른 쓰레드의 진입을 허락하였다. (IsSend 변수 false로 설정)
        3. 큐에 있는 데이터를 할당 해제하고 삭제하였다.

        여기서 2번을 진행한 직후 우연히 2개 이상의 쓰레드가 동시접근하여 Queue에 있는 데이터를 동시에 꺼내서 Queue가 비어버렸다고 판단하고, 2번의 로직을 3번 이후로 옮겨주었더니 오류를 해결할 수 있었다.

        락처리를 세심하게 하지 않은 잘못이었다.

        되게 사소한 실수인 것 같지만 서버 프로그래머 입장에서는 사소한 실수도 용납되지 않는다.

        이런 실수 한번이면 서버가 바로 터져버리기 때문이다. 앞으로 좀 더 세심하고 꼼꼼한 작업을 진행할 수 있도록 신경써야할 것 같다.

         

        그리고 최흥배님의 예제 코드를 분석해보았더니 이전까지는 거의 동일한 방식으로 프로그래밍 되어있었는데

        이번 실습에서는 로직의 차이가 있었다.

        분석 내용은 다음과 같다.

        1. stOverlappedEx 구조체를 Queue에 저장하여 사용한다.
        2. Send가 요청되면 stOverlappedEx 구조체에 값을 채워넣고 Queue에 넣는다. (락처리)
        3. 만약 Queue의 크기가 1이라면 바로 Send를 보낸다.
        4. 1이 아니라면 함수를 빠져나온다.
        5. Send가 완료처리 되면 Queue에서 데이터를 꺼내서 삭제한다. (락처리)
        6. 완료처리 함수에서 Queue에 데이터가 있다면 바로 이어서 Send를 보낸다.

        Queue에 데이터가 1개면 할 일이 있는 상황으로 간주하고 바로 Send를 보내는 처리를 하는 것 같다.

        이렇게 설계하면 장점은 Send 쓰레드에서 반복문을 돌며 Send가 가능한지 체크하는 과정이 빠지므로 CPU 소모가 감소할 것 같다.

         

        마지막으로 깃허브 링크 첨부하고 포스팅을 마치도록 하겠다.

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

        반응형

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

        IOCP 실습 8 채팅 서버 - 패킷 구조 만들기, 로그인 처리  (0) 2023.09.04
        IOCP 실습 7 Echo 서버 - 비동기 Accept 함수 사용하기  (0) 2023.09.01
        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
        다음글
        다음 글이 없습니다.
        이전글
        이전 글이 없습니다.
        댓글
      조회된 결과가 없습니다.
      스킨 업데이트 안내
      현재 이용하고 계신 스킨의 버전보다 더 높은 최신 버전이 감지 되었습니다. 최신버전 스킨 파일을 다운로드 받을 수 있는 페이지로 이동하시겠습니까?
      ("아니오" 를 선택할 시 30일 동안 최신 버전이 감지되어도 모달 창이 표시되지 않습니다.)
      목차
      표시할 목차가 없습니다.
        • 안녕하세요
        • 감사해요
        • 잘있어요

        티스토리툴바