iocp서버 공부를 하던 중 클라가 접속했을 때 정상적으로 큐에 반응은 오나
구조체 OverlappedEx라는 멤버변수의 값이 변경되는 버그가 발생했고
왜 발생하였는가와 어떻게 해결했는가를 공유하려합니다.
OverlappedEx 구조체
enum CompletionType
{
NONE,
RECV,
SEND,
CONNECT,
DISCONNECT,
};
struct OverlappedEx
{
LPOVERLAPPED overlapped = {};
CompletionType type = NONE;
char _buf[BUF_SIZE] = {};
};
OverlappedEx의 구조체입니다.
멤버 변수로는 overlapped와 type, buf가 있습니다.
문제점
unsigned __stdcall IOCP::AcceptThread(void* args)
{
...
OverlappedEx* overlapped = new OverlappedEx();
overlapped->type = CONNECT;
if (acceptEx(_servSocket, _clientSocket, overlapped->_buf, 0,
sizeof(SOCKADDR_IN) + 16, sizeof(SOCKADDR_IN) + 16,
&bytes, (LPOVERLAPPED)overlapped) == FALSE) {
if (WSAGetLastError() != WSA_IO_PENDING) {
std::cerr << "AcceptEx failed: " << WSAGetLastError() << std::endl;
//closesocket(clientSock);
delete overlapped;
}
}
return 0;
}
unsigned __stdcall IOCP::WorkerThread(void* args)
{
Session* session = nullptr;
OverlappedEx* overlapped = nullptr;
DWORD transferredBytes = 0;
while (true)
{
bool ret = GetQueuedCompletionStatus(_iocpHandle, &transferredBytes, (PULONG_PTR)&session, (LPOVERLAPPED*)(&overlapped), INFINITE);
if (ret == true)
{
std::cout << "transferredBytes : " << transferredBytes << std::endl;
switch (overlapped->type)
{
case RECV:
std::cout << "onrecv : " << session->_buf << std::endl;
break;
case SEND:
break;
case CONNECT:
std::cout << "connected\n";
break;
...
}
}
}
보시면 AcceptEx를 호출하기 전 분명히 type을 CONNECT로 초기화를 했는데도
큐에서 받아온 OverlappedEx의 type은 NONE으로 설정이 되어있던것
이때문에 acceptEx로 접속을 수락해도 WorkerThread에서는 switch문을 제대로 탈 수 없었습니다.
원인발견 및 해결방법
결론부터 말씀드리자면 변수 타입문제였습니다.
OverlappedEx의 overlapped 자료형은 LPOVERLAPPED로 되어있었습니다.
이게 왜 문제였냐면 _OVERLAPPED 의 별칭은 OVERLAPPED와 *LPOVERLAPPED가 있습니다.
후자는 *로서 8바이트의 크기를 가지고 전자는 32바이트의 크기를 가집니다.
각 상황을 디스어셈블리로 표현한걸 캡쳐했습니다.
위쪽 이미지가 LPOVERLAPPED 자료형인 경우
아래쪽이 OVERLAPPED 자료형인 경우입니다.
보시면 각 이미지의 두 번째 라인에서 차이점이 보입니다.
해석을 하자면
[rax+8] 위치에 3을 대입, [rax+20h] 위치에 3을 대입
이런식으로 대입하는 주소의 위치 차이가 나기때문에 실제 큐에서 받아온 OverlappedEx의 type이 항상 이상한값으로 채워져있던 것이었죠
따라서 자료형을 LPOVERLAPPED → OVERLAPPED로 바꾸었더니 해결되었습니다!
'C++' 카테고리의 다른 글
[C++] Flatbuffer 사용법 (0) | 2024.11.13 |
---|---|
[C++] Inline함수와 #Define 차이점 (0) | 2024.11.01 |
[C++] find_if 로 특정 클래스 가져오기 (0) | 2024.07.13 |
[C++] String Compare vs strcmp (0) | 2023.07.22 |
[C++] Html Form 인코딩된 데이터 디코딩하기 (0) | 2023.07.05 |