一般的な概要を最初に教えてください。私は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がワーカースレッドによって呼び出されたことを知っています。それは毎回起こることはありませんが、それは起こります。
誰かが私の間違いを教えていただけたら、私は感謝します。