2016-06-19 9 views
0

一般的な概要を最初に教えてください。私は3つのポートを介してデータを受信して​​います。私はソケット、完了ポート、ワーカースレッドを持っています。私はWSARecvを呼び出し、ワーカースレッドプロセスはGetQueuedCompletionStatusとそれに続く私の解析ルーチンReadMsgsを呼び出します。 ReadMsgsが呼び出されたときにバッファが変更されず、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関数(各メッセージが解析されるときにReadMsgsによって呼び出されます)。ここではそのようなクラスがある:

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はその場所での解析を行います。サーバーは最後の改行文字でメッセージを区切り、メッセージ内のフィールドをカンマで区切ります。 ReadMsgsは、カンマと改行が見つかるとヌル文字で置き換え、バッファ内の場所へのポインタの別の配列で各フィールドがどこから始まるかをメモします。これで、ReadMsgsが最後に埋められたバッファの領域の終わりに到達すると、不完全なメッセージが見つかることがあります。これは、バッファの先頭にコピーされ、次の読み取りがメッセージを完了することを期待し、それに応じてwsaBufが変更されます。ただ、部分的メッセージとremsizeを超えた文字へのPCharポイントが残っているバッファのサイズである

wsaBuf.buf = pchar; 
wsaBuf.len = remsize; 
StartRecv(); 

:したがってReadMsgsの終わりには、次のようになります。

私は詳細なサーバーログからアプリケーションに送信されたメッセージを知っています。区切り文字をヌル文字に置き換えることで、バッファのどの部分が処理されたかを簡単に知ることができます。バッファをファイルに保存して調べることで、ReadMsgsが呼び出された後にバッファが更新されたことがわかります。また、上記のコードに示されていないログメッセージによって、私はReadMsgsがワーカースレッドによって呼び出されたことを知っています。それは毎回起こることはありませんが、それは起こります。

誰かが私の間違いを教えていただけたら、私は感謝します。

答えて

0

回答があります。私は、StartRecvとCallback_Socketの両方でReadMsgsを呼び出す必要があります。 StartRecvでは、WSARecvが0を返し、WSARecvによって転送が完了したことを示すReadMsgsを呼び出します。私は、転送がWSARecvで完了した場合、GetQueuedCompletionステータスが関与しないと考えていました。しかし、GetQueuedCompletionStatusが完了した読み取りに応答して返された場合、前回の仮説と同様に、収集したログデータを説明するReadMsgへの重複呼び出しがあります。

私はStartRecvのReadMsgへの呼び出しを削除しました。コードは正しく動作しています。

私に否定的な投票をした紳士のおかげです。それは、私が説明した行動がこれまでに観察されていなかったことを示唆しており、そうは思われません。それは私を新しい方向に考えさせてくれました。時には、経験豊富なバンの方がボリュームを話すことがあります。

関連する問題