Today I Learn
[TIL][C++] 250508 MMO 서버 개발 14일차: Service에서 SessionFactory의 필요성, ::getpeername
pledge24
2025. 5. 9. 00:41
주의사항: 해당 글은 일기와 같은 기록용으로, 다듬지 않은 날것 그대로인 글입니다.
Service에서 SessionFactory의 필요성
- SessionFactory란 세션을 만드는 하나의 공장으로, 호출 시 세션을 반환한다.
using SessionFactory = function<SessionRef(void)>;
- 위 코드에서 알 수 있듯, SessionFactory는 단순한 functor를 using으로 이명을 붙여준 것이다. 그렇다면 SessionFactory를 따로 만들어서 Session을 생성하는 것일까? 그냥 Session 클래스를 객체화하여 사용하면 되는 것이 아닌가?
SessionRef Service::CreateSession()
{
// 각 하위 서비스가 등록한 sessionFactory로
// 세션을 생성 및 반환한다.
SessionRef session = _sessionFactory();
session->SetService(shared_from_this());
if (_iocpCore->Register(session) == false)
return nullptr;
return session;
}
- 같은 서비스를 상속받더라도 각 서비스는 서로 다른 타입의 세션을 가질 수 있다. 서비스는 CreateSession으로 서비스 내 세션을 생성하는 역할을 맡는데 상위 클래스인 서비스를 정의하는 경우 하위 클래스에서 사용하는 세션의 종류에 대해 미리 알 수가 없다.
- 따라서, 서비스는 각 하위 서비스가 사용할 세션을 올바르게 생성하는 일련의 과정을 SessionFactory에 저장해 달라 요구하고, CreateSession시 SessionFactory를 호출함으로써 각 서비스에 맞는 세션을 생성할 수 있게 된다.
가상 함수를 사용해도 되지 않는가?
- 안될 건 없다. 하지만 CreateSession을 하는 과정 중 대부분이 상위 클래스인 서비스에서 처리할 수 있다. 따라서, 하위 서비스 클래스에서 override 해서 사용한다면, 각 서비스에서 상위 클래스가 처리하는 같은 내용의 코드를 여러 번 작성해야 하므로 그다지 좋은 선택이 되지 않는다.
- 다른 방법들로 함수를 쪼개서 처리하는 등이 있을 수 있겠지만 SessionFactory방식만큼 깔끔하게 떨어지지는 않는 것 같다…
::getpeername
SOCKADDR_IN sockAddress;
int32 sizeOfSockAddr = sizeof(sockAddress);
if (SOCKET_ERROR == ::getpeername(session->GetSocket(), OUT reinterpret_cast<SOCKADDR*>(&sockAddress), &sizeOfSockAddr))
{
RegisterAccept(acceptEvent);
return;
}
- getpeername은 특정 소켓과 연결된 상대 호스트의 소켓 주소를 알아내는 함수로, 연결된 소켓과 사용한 소켓 주소 타입의 변수(sockAddress)를 넣어주면, sockAddress에 상대 호스트의 소켓 주소가 저장된다.
- 이를 통해 Session에서 상대 호스트 주소를 멤버 변수로 들고 있을 수 있다.