먼저 일반 개요를 알려 드리겠습니다. 3 개의 포트를 통해 데이터를 수신합니다. 소켓, 완료 포트 및 각각에 대한 작업자 스레드가 있습니다. WSARecv를 호출하고 작업자 스레드 프로세스는 GetQueuedCompletionStatus를 호출하고이어서 구문 분석 루틴 ReadMsgs를 호출합니다. ReadMsg가 호출 될 때 버퍼가 변경되지 않고 ReadMsg가 버퍼를 처리하는 동안 버퍼가 업데이트되는 경우가 있습니다. GetQueuedCompletionStatus가 반환 한 처리 바이트 수는 업데이트가 발생할 때 업데이트에 대해 정확합니다.GetQueuedCompletionStatus가 조기에 종료 됨 (또는 생각 했음)
왜 이런 일이 발생할 수 있으며 내가 뭘 잘못하고 있는지 알 수 있습니까? 가장 관련성이 높은 코드를 보여 드리겠습니다. 더 많은 코드가 필요하면 구체적으로 작성하십시오. 내 기본 소켓 클래스는 (내가 관련성이없는 나에게 보인다 세부 사항을 생략했다. 나는 또한 모든 오류 검사를 생략했다.)
class Socket_Base : public OVERLAPPED
{
public:
Socket_Base()
{
// Initialize base OVERLAPPED object
Internal = 0;
InternalHigh = 0;
Offset = 0;
OffsetHigh = 0;
hEvent = WSACreateEvent();
// Initialize addr structure
ZeroMemory(&addr, sizeof(struct sockaddr_in));
// Create the completion port
hCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
// Create the worker thread and bind it to the callback function and the completion port
hThread = (HANDLE)_beginthreadex(NULL, 0, Callback_Socket, hCP, 0, NULL);
// Create the socket
Sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
// Bind the socket to the completion port
CreateIoCompletionPort((HANDLE)Sock, hCP, 0, 0);
}
void Connect() { WSAConnect(Sock, (SOCKADDR*)(&addr), sizeof(addr), NULL, NULL, NULL, NULL);}
void StartRecv()
{
DWORD Flags = 0;
DWORD numBytes = 0;
if (WSARecv(Sock, &wsaBuf, 1, &numBytes, &Flags, (OVERLAPPED*)this, NULL) == 0) ReadMsgs(numBytes);
}
int ReadMsgs(int NumBytes);
protected:
virtual ~Socket_Base() {}
virtual void ProcessMsg() = 0;
struct sockaddr_in addr;
SOCKET Sock;
HANDLE hCP;
WSABUF wsaBuf;
HANDLE hThread;
char *readBuf;
int bufsize;
};
각 포트는 자신의 파생 소켓 클래스는 포트 번호에 의해 distinguised했다 다음과 같습니다 가상 ProcessMsg 기능 (각 메시지가 구문 분석 될 때 ReadMsg에 의해 호출 됨).
이class Socket_Admin : public Socket_Base
{
public:
static const int bufcap = 1024;
Socket_Admin::Socket_Admin() : Socket_Base()
{
// Buffer
readBuf = new char[ bufcap];
// The socket
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = htons(9300);
wsaBuf.buf = readBuf;
wsaBuf.len = bufcap;
}
~Socket_Admin();
void ProcessMsg();
};
작업자 스레드 프로세스가 내가 설명해야 한 가지가있다
unsigned int Callback_Socket(void *lpParameter)
{
HANDLE hCP = (HANDLE)lpParameter;
DWORD NumBytes = 0;
ULONGLONG CompletionKey;
WSAOVERLAPPED *pOverlapped;
while (GetQueuedCompletionStatus(hCP, &NumBytes, &CompletionKey, &pOverlapped, INFINITE) && CompletionKey == 0)
{
Socket_Base *pTCP = (Socket_Base*)pOverlapped;
if (NumBytes > 0) pTCP->ReadMsgs(NumBytes);
NumBytes = 0;
}
return 0;
}
입니다 : 여기에 하나 개의 클래스입니다. ReadMsgs는 해당 구문 분석을 수행합니다. 서버는 최종 줄 바꾸기 문자로 메시지의 범위를 정하고 메시지 내의 필드를 쉼표로 구분합니다. ReadMsg는 쉼표와 줄 바꿈을 찾을 때 null 문자로 바꾸고 버퍼의 위치에 대한 포인터의 개별 배열에서 각 필드의 시작 위치를 기록합니다. 이제 ReadMsg가 마지막으로 채워진 버퍼 영역의 끝에 도달하면 불완전한 메시지가 발견되는 경우가 있습니다. 이것은 버퍼의 시작 부분으로 복사되고, 다음 읽기가 메시지를 완료 할 것으로 예상되며 그에 따라 wsaBuf가 수정됩니다. 따라서 ReadMsgs의 끝은 다음과 같다 :
단지 부분 메시지 remsize 넘어 문자를 PChar 포인트 남은 버퍼 사이즈wsaBuf.buf = pchar;
wsaBuf.len = remsize;
StartRecv();
.
나는 메시지 세부 서버 로그에서 내 응용 프로그램으로 전송 된 것을 알고있다. 분리.자를 널 문자로 대체하면 처리 된 버퍼의 부분을 쉽게 알 수 있습니다. 버퍼를 파일에 저장하고 검사하여 ReadMsgs가 호출 된 후 버퍼가 업데이트되었음을 알 수 있습니다. 또한 위의 코드에 나와 있지 않은 로그 메시지로 인해 이러한 경우 ReadMsgs가 작업자 스레드에 의해 호출되었음을 알았습니다. 그것은 매번 발생하지 않지만 일어난다. 누군가가 내 실수가 무엇인지 말해 줄 수 있다면
, 나는 감사하겠습니다.