2016-06-19 3 views
0

먼저 일반 개요를 알려 드리겠습니다. 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가 작업자 스레드에 의해 호출되었음을 알았습니다. 그것은 매번 발생하지 않지만 일어난다. 누군가가 내 실수가 무엇인지 말해 줄 수 있다면

, 나는 감사하겠습니다.

답변

0

답변이있을 수 있습니다. StartRecv와 Callback_Socket 모두에서 ReadMsg를 호출합니다. StartRecv에서 WSARecv가 0을 반환하면 WSARecv에 의해 전송이 완료되었음을 나타내는 ReadMsgs가 호출됩니다. WSARecv에서 전송이 완료되면 GetQueuedCompletion 상태가 관련되지 않는다고 생각했습니다. 그러나 GetQueuedCompletionStatus가 완료된 읽기에 대한 응답으로 반환 된 경우, 필자는 이전의 가설과 마찬가지로 수집 한 기록 된 데이터를 설명하는 ReadMsgs에 대한 중복 호출을가집니다.

나는 StartRecv에서 ReadMsgs에 대한 호출을 제거했습니다. 코드가 제대로 작동하고 있습니다.

나를 싫어하는 신사에게 감사의 말을 전합니다. 그것은 내가 설명한 행동이 이전에는 관찰되지 않았기 때문에 그렇게 될 가능성이 거의 없다는 것을 나에게 제안했다. 그것은 저를 새로운 방향으로 생각하게했습니다. 때로는 경험이 많은 밴이 볼륨을 말하는 사람으로부터 그냥 꿀꺽 꿀꺽하기 만합니다.