- IOCP Echo Server 10 - ConfigFile Parser2024년 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으로 변환하여 반환
- 다른 타입들도 마찬가지
파싱
- 파일 오픈
- read 옵션과 인코딩은 UTF-16LE 옵션으로 엶
- 파일 사이즈 구하기
size_t fileBytes; fseek(pFile, 0, SEEK_END); fileBytes = ftell(pFile); fseek(pFile, 0, SEEK_SET);
파일 읽은만큼 fread_s 읽기 호출
- binary 옵션으로 열지 않았기 때문에 file 크기보다 적게 읽힘
- 캐리지 리턴과 BOM이 빠짐
- binary 옵션으로 열었다가 BOM 때문에 버그가 발생해서 옵션을 제거했음
파일을 닫고 읽은 버퍼의 끝에 \0 종료 문자 삽입
띄어쓰기와 탭 제거
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, 삭제할문자);
- 두 반복자 사이의 문자를 삭제함
- 동작방식
- 문자를 삭제하고 - 삭제가 아닌 덮어쓰기라고 하는게 더 정확한 듯
- 뒤의 문자를 앞으로 복사함
- 반환 값은 삭제한 문자열의 마지막 위치의 다음 위치의 반복자임
- aaabbbccc 에서 a 문자 삭제
- bbbcccccc 가 되고
- 4번째 c의 위치의 반복자가 반환됨
- 따라서 std::string의 erase를 통해 뒤의 남은 문자를 지워주어야 함
std::erase(startIt, endIt)
- startIt 부터 endIt까지의 문자를 지움
- std::remove의 반환 값을 startIt에 넣고 endIt에는 str.end()를 넣어 남은 문자를 삭제함
이렇게 탭 문자와 띄워쓰기를 제거함
- // 주석 제거
std::string::find(문자);
- 문자를 찾아 string 내의 오프셋을 알려줌
- find를 통해 //과 \n 문자의 오프셋을 찾음
- 이렇게 찾은 문자를 std::erase를 통해 지움
여기서의 std::erase는 위에서 erase랑은 다른 오버로딩 버전
- std::erase(offset, count);
- startOffset, endOffset을 인자로 받는 줄 알고 실수를 저질렀었음
- cppreference를 찾아보고 offset, count 임을 알아냄
위에서 사용한 std::string::erase(std::remove(), end)를 통해 \n 문자 제거
- 한줄 주석을 지웠으므로 \n을 지워도 됨
- 만약 :, ; 같은 끝을 알려주는 문자를 사용하지 않았다면 \n을 지우면 안되지만 내 파일 형식에서는 사용하므로 지워도 됨
여러줄 주석 제거
- 위에서 사용한 std::string의 함수를 사용하면 쉽게 제거 가능
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일 동안 최신 버전이 감지되어도 모달 창이 표시되지 않습니다.)