Giter VIP home page Giter VIP logo

edu_cpp_iocp's Introduction

단계 별로 IOCP 실습

  • 코드에 버그가 있을 수 있다.(버그를 잡는 것도 공부!)
  • Modern C++을 적극적으로 사용하는 것을 추천한다.
  • 'Tutorial/ChatServerWithLogger' 있는 프로젝트는 채팅 서버에 plog 라이브러리를 사용하고 있으며, Windows Event Log에 로그 데이터를 기록할 수 있다.
  • Visual Studio 2022를 사용한다(하위 버전으로 변경해도 코드 변경은 없다)

실습 단계

실습을 하기 전에 꼭 IOCP에 대해 학습을 한다.
IOCP는 오래된 기술로 서적에서 다루기도 했고, 특히 네이버에서 검색해도 많은 자료를 찾을 수 있다(네이버 검색하면 한글 자료)

  • 1 단계. 가장 간단한 IOCP 서버. Echo 서버 코드 만들기
    • IOCP API 동작에 대해서 이해할 수 있다.
  • 2 단계. OverlappedEx 구조체에 있는 char m_szBuf[ MAX_SOCKBUF ]를 stClientInfo 구조체로 이동 및 코드 분리하기
    • 앞 단계에는 OverlappedEx 구조체에 m_szBuf가 있어서 불 필요한 메모리 낭비가 발생함
  • 3 단계. 애플리케이션과 네트워크 코드 분리하기
    • IOCP를 네트워크 라이브러리화 하기 위해 네트워크와 서버 로직 코드를 분리한다.
    • 연결, 끊어짐, 데이터 받음을 애플리케이션에 전달하기
  • 4 단계. 네트워크와 로직(패킷 or 요청) 처리 각각의 스레드로 분리하기
    • Send를 Recv와 다른 스레드에서 하기
    • send를 연속으로 보낼 수 있는 구조가 되어야 한다.
  • 5 단계. 1-Send 구현하기
    • 버퍼에 쌓아 놓고, send 스레드에서 보내기.
  • 6 단계. 1-Send 구현하기
    • queue에 담아 놓고 순차적으로 보내기.
  • 7 단계. 비동기 Accept 사용하기
    • 6단계까지는 Accept 처리를 동기 I/O로 했다. 이것을 비동기I/O로 바꾼다. 이로써 네트워크 동작이 모두 비동기 I/O가 된다
    • 6단계에서 이어서 기능을 구현한다.
  • 8 단계. 채팅 서버 만들기 (ChatServer_01)
    • 패킷 구조 사용하기, 로그인
  • 9 단계. 로그인 때 Redis 사용하기 (ChatServer_02)
  • 10 단계. 방 입장, 방 나가기, 방 채팅 구현하기 (ChatServer_03)

더 진행 한다면...

  • 11 단계. 최적화 하기
    • GetQueuedCompletionStatusEx 버전 사용하기
    • 서버에서 사용하는 설정을 입력 받기
    • 동적 할당을 최소화 하기
    • 링버퍼 구현 추가(덮어 쓰기 방지)
    • Lock 사용 범위를 줄이거나 좀 더 가벼운 Lock 사용하기
    • 더미 클라이언트로 테스트 하기
  • 12 단계. Network, Content, Host 각 레이어로 프로젝트 나누기
    • Network, Content는 각각 정적 라이브러리로 만든다.
    • Host는 콘솔 프로젝트. Network, Content 라이브러리를 사용한다.

참고 글 모음

edu_cpp_iocp's People

Contributors

jacking75 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

edu_cpp_iocp's Issues

User::SetPacketData, User::GetPacket 멀티 쓰레드 이슈

WorkThread에서는 User::SetPacketData 호출되고
ProcessPacketThread에서는 User::GetPacket 호출되는데
서로 다른 쓰레드에서 lock없이 SetPacketData, GetPacket 함수 안 쪽에서 User의 멤버 변수(공유자원)을 참조하고 변경까지 하고 있는데 이 부분 문제가 안되는건가요?

WorkThread에서 그냥 User::SetPacketData와 User::GetPacket 하는 부분을 같이 진행하고
완성된 패킷만 별도의 큐에 담고 ProcessPacketThread에서는 완성된 패킷만 큐에서 빼오는 방식으로하면 어떨까요? (큐에다 lock걸어야해서 성능 이슈? 생길 수도)

저렇게 분리하신 이유가 있으시면 그게 궁금하고 제가 제시한 방안은 어떻게 생각하시는지 궁금합니다.

그리고 11단계, 12단계는 진행 하실 생각이 있으신지..? 아니면 그냥 공부하는 사람한테 수행과제로 내신건가요..?

항상 감사합니다~!

AccepterThread 용도에 대해서 궁금한 점이 있어서 질문 남겨요.

//사용자의 접속을 받는 쓰레드
void AccepterThread()
{
while (mIsAccepterRun)
{
auto curTimeSec = std::chrono::duration_caststd::chrono::seconds(std::chrono::steady_clock::now().time_since_epoch()).count();

		for (auto client : mClientInfos)
		{
			if (client->IsConnectd())
			{
				continue;
			}

			if ((UINT64)curTimeSec < client->GetLatestClosedTimeSec())
			{
				continue;
			}

			auto diff = curTimeSec - client->GetLatestClosedTimeSec();
			if (diff <= RE_USE_SESSION_WAIT_TIMESEC)
			{
				continue;
			}

			client->PostAccept(mListenSocket, curTimeSec);
		}
		
		std::this_thread::sleep_for(std::chrono::milliseconds(32));
	}
}

일단 AccepterThread 쓰레드 소스 코드 내용이에요.

질문 1. 왜 clientInfo_->Close함수가 호출 될 때 소켓을 정리 해주고 바로 clientInfo_->PostAccept() 호출 하면 될 것같은데
왜 별도로 AccepterThread 쓰레드를 둬서 관리를 하는지 궁금합니다.

질문 2. RE_USE_SESSION_WAIT_TIMESEC 이 부분은 왜 3초이고 왜 체크 하는지 궁금합니다. 소켓을 종료하고 난 후에 여유 시간을 둬야 하나요? 그럼 왜 둬야 하는지 궁금해요

질문 3. std::this_thread::sleep_for(std::chrono::milliseconds(32)); 에서 밀리세컨드값이 왜 32인지 궁금합니다. 큰의미는 없을 것 같긴한데 혹시 32밀리세컨드가 최적의 시간이라서 그런건지? 잘 몰라서 여쭤봐요

예전에 흥배님 c#서버 오프라인 하루 강의 하셨을 때 뵀었는데 항상 많은 도움을 받네요 감사합니다.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.