우선 한국 ip인지 외국 ip인지 확인해야하므로 기준 값이 필요하니까 대륙별 인터넷 레지스트리(RIR, Regional Internet registry )에서 대륙별 ip 범위를 curl을 이용해 가져온다. 가져온 ip를 활용해 서버에 접속한 클라의 ip를 검사해서 한국인지 외국인지 검사하여 외국이면 거절한다.
오브젝트풀은 소프트웨어 개발에서 성능 최적화를 위해 사용되는 디자인 패턴이다. 객체 생성과 소멸에 드는 비용을 줄이기 위해 미리 생성된 객체들을 풀(Pool)에 보관하고 재사용하는 방식이다.
📌 핵심 개념
ObjectPool의 기본 아이디어는 비용이 많이 드는 객체들을 필요할 때마다 새로 생성하지 않고, 미리 생성해두고 재사용하는 것이다. 객체를 사용한 후에는 다시 풀로 반환하여 다른 곳에서 재사용할 수 있게 한다.
📌 동작 원리
초기화: 풀 생성 시 일정 수의 객체를 미리 생성하여 풀에 저장
대여(Rent): 객체를 요청하면 풀에서 사용 가능한 객체를 제공
반환(Return): 사용이 끝난 객체를 다시 풀로 반환
재사용: 반환된 객체는 초기화된 후 다른 요청에서 재사용
앞서 작업하던 채팅서버에서 Packet을 오브젝트풀을 사용해 할당하려고한다.
Packet은 멀티스레드에서 사용해야하기 때문에 앞서 포스팅한 Lock-free Stack을 이용해 오브젝트 풀을 구현했다.
Alloc 함수
template<class DATA>
DATA* ObjectPool<DATA>::Alloc(void)
{
Node* AllocNode;
CheckNode Top;
int AllocCount = _AllocCount;
int UseCount = _UseCount;
InterlockedIncrement(&_UseCount);
if (AllocCount > _UseCount) //사용 할 수 있는 블럭이 있는 경우
{
LONG64 LockFreeCheckCount = InterlockedIncrement64(&_LockFreeCheckCount);
do
{
Top.NodeCheckValue = _TopNode->NodeCheckValue;
Top.TopNode = _TopNode->TopNode;
AllocNode = Top.TopNode;
} while (!InterlockedCompareExchange128((volatile LONG64*)_TopNode, LockFreeCheckCount, (LONG64)_TopNode->TopNode->NextBlock, (LONG64*)&Top));
new (AllocNode) DATA;
}
else //사용 할 수 있는 블럭이 없을 경우
{
//새로운 노드 할당해주고 생성자 호출 후 넘겨줌
AllocNode = (Node*)malloc(sizeof(Node));
memset(AllocNode, 0, sizeof(Node));
new (AllocNode) DATA;
/*
할당 수와 사용 수를 늘려준다.
*/
InterlockedIncrement(&_AllocCount);
}
return (DATA*)&AllocNode->Data;
}
AllocCount와 UseCount를 비교해서 새로 할당해주거나 Stack으로 관리하는 데이터를 하나꺼내서 반환한다.
CAS를 사용해 자료구조의 아이템을 변경할 때, 포인터가 시스템에 의해 재사용되면서 생기는 문제를 말한다.
예를 들어보자.
ThreadA, ThreadB, ThreadC가 있고,
{ 4, 3, 2, 1 } 순서로 네 개의 수를 삽입한 스택이 있다고 할때, ThreadA에서 pop을 해서 4를 빼고, 3을 top으로 지정하는 작업을 완료하기 전에, ThreadB에서 접근해서 pop을 2번 진행한후, ( { 2, 1 } ) ThreadC에서 push를 해서 4를 다시 넣은 후 ( { 4,2,1} ), ThreadA에서 CAS를 하면 ThreadA에서는 4가 맨위에 있기 때문에 아무런 문제가 발생하지 않은 것처럼 보인다. 따라서 3을 top으로 만들게 되는데, 3은 이미 제거된 데이터이기 때문에 3을 top으로 보면 안된다.