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

        IOCP Echo Server 10 - ConfigFile Parser

        목적

        서버 설정 정보들이 헤더 파일에 기입되어 있었음

        • IP 혹은 포트 등이 변경될 때마다 재빌드 해야하는 단점
        • 이걸 극복하기 위해 나만의 파일 형식(?)을 정의하고 파싱하는 파서 구현
          • 이런 파일 형식이 이미 있을 수 있음
          • 어디서 본 형식일수도...

        std::string을 별로 사용해본적이 없으므로

        • 모던 C++의 string 사용 연습 또한 목적

        파일 형식 정의

        // 주석기능
        /*
            여러줄 주석~~~
        */
        
        ClassName1: // 주석
            - Key1 = ValueString; // 주석
            - Key2 = 1234; /*
        
            중간 주석 끼워넣기
        */
        
        ClassName2: /*
        
            중간 주석 끼워넣기
        */
            - Key1 = ValueString;
            - Key2 = 1234; // 주석
        
        Server:
            - IP = 0.0.0.0;
            - Port = 10611;
        • 주석 기능 C/C++에 있는 그것
          • //주석 내용, /* 주석 내용 */
        • 클래스 정의
          • ClassName: 클래스 이름 뒤에는 무조건 : 붙이기
        • Key와 Value
          • 무조건 -로 시작하고 Key=Value 형태 그리고 끝에는 무조건 ; 붙이기

        문자의 마지막 문자(;, :)의 있고 없고가 파서 구현의 난이도 차이를 만듦

        • 이 문자가 있으면 라인에 상관없이 붙여쓸 수 있지만 없다면 무조건 \n가 필요
        • 파일의 형식이 조금 딱딱해짐

        파서 구현

        Loader 클래스 선언

        // 싱글 스레드에서만 접근될 것
        class CMyFileLoader
        {
        public:
            // 기본적으로 std::wstring 으로 저장
            VOID Parse(const WCHAR *fileName);
        
            // 필요하면 더 구현할 것
            BOOL        Load(const WCHAR *classStr, const WCHAR *keyStr, USHORT *outValue);
            BOOL        Load(const WCHAR *classStr, const WCHAR *keyStr, INT *outValue);
            BOOL        Load(const WCHAR *classStr, const WCHAR *keyStr, std::string *str);
            BOOL        Load(const WCHAR *classStr, const WCHAR *keyStr, std::wstring *wstr);
        
        private:
            // 파싱해서 데이터를 가지고 있을 자료구조
            std::unordered_map<std::wstring, std::unordered_map<std::wstring, std::wstring>> m_parsedDatas;
        };
        • 멀티스레드 설계는 고려하지 않음
          • 처음 main 함수가 시작할 때 필요한 설정 정보만 초기화하고 해제할 클래스임
        • 파싱을 한번에 전부 마친 뒤 Load를 통해 원하는 항목을 빠르게 불러올 수 있는 구조
          • std::unordered_map 사용
        • 기본적으로는 std::wstring을 들고 있다가 std::string의 반환이 필요하면 std::string으로 변환하여 반환
          • 다른 타입들도 마찬가지

        파싱

        1. 파일 오픈
          • read 옵션과 인코딩은 UTF-16LE 옵션으로 엶
        2. 파일 사이즈 구하기
        size_t fileBytes;
        fseek(pFile, 0, SEEK_END);
        fileBytes = ftell(pFile);
        fseek(pFile, 0, SEEK_SET);
        1. 파일 읽은만큼 fread_s 읽기 호출

          • binary 옵션으로 열지 않았기 때문에 file 크기보다 적게 읽힘
          • 캐리지 리턴과 BOM이 빠짐
            • binary 옵션으로 열었다가 BOM 때문에 버그가 발생해서 옵션을 제거했음
        2. 파일을 닫고 읽은 버퍼의 끝에 \0 종료 문자 삽입

        3. 띄어쓰기와 탭 제거

        wStr.erase(remove(wStr.begin(), wStr.end(), L'\t'), wStr.end());
        wStr.erase(remove(wStr.begin(), wStr.end(), L' '), wStr.end());
        • 이렇게 std::string의 함수를 사용하면 문자열의 모든 특정 문자를 제거할 수 있음

        std::remove(startIt, endIt, 삭제할문자);

        • 두 반복자 사이의 문자를 삭제함
        • 동작방식
          1. 문자를 삭제하고 - 삭제가 아닌 덮어쓰기라고 하는게 더 정확한 듯
          2. 뒤의 문자를 앞으로 복사함
        • 반환 값은 삭제한 문자열의 마지막 위치의 다음 위치의 반복자임
          • aaabbbccc 에서 a 문자 삭제
          • bbbcccccc 가 되고
          • 4번째 c의 위치의 반복자가 반환됨
        • 따라서 std::string의 erase를 통해 뒤의 남은 문자를 지워주어야 함

        std::erase(startIt, endIt)

        • startIt 부터 endIt까지의 문자를 지움
        • std::remove의 반환 값을 startIt에 넣고 endIt에는 str.end()를 넣어 남은 문자를 삭제함

        이렇게 탭 문자와 띄워쓰기를 제거함

        1. // 주석 제거

        std::string::find(문자);

        • 문자를 찾아 string 내의 오프셋을 알려줌
        • find를 통해 //과 \n 문자의 오프셋을 찾음
        • 이렇게 찾은 문자를 std::erase를 통해 지움

        여기서의 std::erase는 위에서 erase랑은 다른 오버로딩 버전

        • std::erase(offset, count);
        • startOffset, endOffset을 인자로 받는 줄 알고 실수를 저질렀었음
        • cppreference를 찾아보고 offset, count 임을 알아냄
        1. 위에서 사용한 std::string::erase(std::remove(), end)를 통해 \n 문자 제거

          • 한줄 주석을 지웠으므로 \n을 지워도 됨
          • 만약 :, ; 같은 끝을 알려주는 문자를 사용하지 않았다면 \n을 지우면 안되지만 내 파일 형식에서는 사용하므로 지워도 됨
        2. 여러줄 주석 제거

          • 위에서 사용한 std::string의 함수를 사용하면 쉽게 제거 가능
        3. className 파싱하고 key, value 쌍 찾아서 map에 등록

        값 Load

        BOOL        Load(const WCHAR *classStr, const WCHAR *keyStr, USHORT *outValue);
        • classStr과 keyStr을 받아서 값을 찾음
        • out 파라미터를 받아 거기에 값을 받아오는 형식으로 구현

        Out 파라미터의 장점

        • 사실 return으로 받는 것의 단점
        • return으로 받는 경우 받는 값의 타입이 정수 같은 숫자일 경우
          • 값을 찾지 못했을 때 어떤 값으로 판단해야하는지에 대한 애매함
          • 이러한 이유 때문에 Out 파라미터를 선호함
            • 주관적인 개인 의견임

        서버에 적용

        지금까지 만들었던 서버에 적용시켜봄

        /*
            Server Config File
                * 서버 설정에 필요한 정보를 여기에 입력합니다.
                * 인코딩은 UTF-16 LE로 설정해야 합니다.
        */
        
        Server:
            - IP = 0.0.0.0;
            - PORT = 6000;
        • 서버 config 파일을 만들고
        • Load 하여 사용
        • System 적인 옵션도 설정하려 했으나
          • 고정크기 배열을 사용 중이므로 이건 설정하지 못했음
            • 포인터로 바꾸면되긴 하지만..

        main 함수 초기에서 값을 로드

        int main()
        {
            std::string openIP;
            USHORT openPort;
        
            {
                CMyFileLoader serverConfigLoader;
                serverConfigLoader.Parse(L"ServerConfig.conf");
        
                serverConfigLoader.Load(L"Server", L"IP", &openIP);
                serverConfigLoader.Load(L"Server", L"PORT", &openPort);
            }
        
          // ... 서버 시작 코드
        }
        • 스코프({})를 지정함으로 FileLoader의 수명을 제한
        • 초기에만 사용하고 서버가 시작할 시점에는 모두 해제된 상태

        다음 목표

        • 락프리 스택
          • 이제 슬슬 락을 걸었던 자료구조를 락프리 자료구조로 변경할 것
        반응형

        '포트폴리오' 카테고리의 다른 글

        IOCP Echo Server 12 - 락 프리 큐 적용  (0) 2024.11.24
        IOCP Echo Server 11 - 락 프리 스택 적용  (0) 2024.11.19
        IOCP Echo Server 09 - Socket Pool  (0) 2024.11.14
        IOCP Echo Server 08 - AcceptEx 스레드 다시 분리 + 유저 APC 큐  (0) 2024.11.13
        IOCP Echo Server 07 - 비동기 Accept  (0) 2024.11.12
        다음글
        다음 글이 없습니다.
        이전글
        이전 글이 없습니다.
        댓글
      조회된 결과가 없습니다.
      스킨 업데이트 안내
      현재 이용하고 계신 스킨의 버전보다 더 높은 최신 버전이 감지 되었습니다. 최신버전 스킨 파일을 다운로드 받을 수 있는 페이지로 이동하시겠습니까?
      ("아니오" 를 선택할 시 30일 동안 최신 버전이 감지되어도 모달 창이 표시되지 않습니다.)
      목차
      표시할 목차가 없습니다.
        • 안녕하세요
        • 감사해요
        • 잘있어요

        티스토리툴바