プログラミングメモ →目次

名前付きパイプ(複数インスタンス)(VC++)

Named Pipe 

クライアントが複数存在するプロジェクトの場合は、クライアント間で情報を転送する為に、名前付きパイプを複数個のインスタンスの形で使います。例えば、クライアントの数は三つの場合は、同じ名前のパイプを三回にを作成します。サーバー側で、一つのクライアントから受信したデータを別のクライアントに転送することができるので、便利な通信手段とは言えます。

#define NMAXINSTANCES 3
HANDLE g_hPipeListen[NMAXINSTANCES] = {INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
                                       INVALID_HANDLE_VALUE};
HANDLE hThreadListen[NMAXINSTANCES] = {NULL,NULL,NULL};
void CreateListenPipeThread()
{
    bEndProc = FALSE;
    for (int i = 0; i < NMAXINSTANCES; i ++)
    {
        g_hPipeListen[i] = CreateNamedPipe("\\\\.\\pipe\\test", 
                                           PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 
                                           PIPE_TYPE_BYTE | PIPE_WAIT, 
                                           NMAXINSTANCES, 0, 0, 
                                           NMPWAIT_WAIT_FOREVER, 0);
        hThreadListen[i] = CreateThread(NULL, 0, ListenPipeThread,
                                        (LPVOID)i, 0, NULL);
        hThreadWrite[i] = CreateThread(NULL, 0, WritePipeThread, (LPVOID)i, 0, NULL);
        hEventWrite[i] = CreateEvent(NULL, TRUE, FALSE, NULL);
    }
}
パイプのインスタンスを作りながら、インスタンス毎に、リスニング(=パイプ接続待ち)のスレッドとライトのスレッドを作ります。メルチスレッド無しで、パイプを 利用できないですね。
DWORD WINAPI ListenPipeThread(LPVOID lpParam)
{
    int iNo = (int)lpParam;
    while (!bEndProc)
    {
        OVERLAPPED    ovlp;
        HANDLE hEvent;
        memset(&ovlp, 0, sizeof(OVERLAPPED));
        hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
        ovlp.hEvent = hEvent;
        if (!ConnectNamedPipe(g_hPipeListen[iNo], &ovlp))
        {
            if (GetLastError() == ERROR_IO_PENDING)
            {
                WaitForSingleObject(hEvent, INFINITE);
            }
            else if (GetLastError() == ERROR_PIPE_CONNECTED)
            {
                CloseHandle(hEvent);
                continue;
            }
            bListening[iNo] = TRUE;                    
            ReadPipe(iNo);    
        }
        DisconnectNamedPipe(g_hPipeListen[iNo]);
        bListening[iNo] = FALSE;                    
    }
    return 0;
}
リスニングのスレッドの中で、まずクライアントプロセスがパイプのインスタンスに接続してくるのを待機します。接続されたら、繰り返してパイプをリ ードをして見ます。この間、クライアント側などの原因でリードが不可能になれば、今現在の接続を自ら切断して、またパイプのインスタンスに接続してくるのを待機すること路から繰り返します。パイプのリードは下記のようです。
void ReadPipe(int iNo)
{
    while (!bEndProc && bListening[iNo])
    {
        OVERLAPPED    ovlp;
        HANDLE hEvent;
        memset(&ovlp, 0, sizeof(OVERLAPPED));
        hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
        ovlp.hEvent = hEvent;
            
        DWORD nBytes = 0;
        char buff[1024];
        memset(buff, NULL, sizeof(buff));

        BOOL bRet = ReadFile(g_hPipeListen[iNo], buff, 10, &nBytes, &ovlp);
        if (!bRet)
        {
            if (GetLastError() == ERROR_IO_PENDING)
            {
                WaitForSingleObject(hEvent, INFINITE);
                bRet = GetOverlappedResult(g_hPipeListen[iNo], &ovlp, 
                                           &nBytes, TRUE);
            }
        }
        CloseHandle(hEvent);
        if (bRet)
        {
            if (nBytes)
            {
                TRACE("受信%d: %s\r\n", iNo, buff);

                for (int i = 0; i < NMAXINSTANCES; i ++)
                {
                    if (i != iNo && g_hPipeListen[i] != INVALID_HANDLE_VALUE)
                    {
                        strcpy(send_buff[i], buff);
                        SetEvent(hEventWrite[i]);
                        Sleep(10);
                    }    
                }
            }
        }
        else
        {
            break;
        }
    }
}
OVERLAPPEDで受信をします。一つのクライアントから受信したら、他のクライアントへ転送します。受信エラーが発生するまで繰り返します。

テスト用のソース(pipetest.cpp)