windows 异步管道读写

该代码示例展示了在Windows环境中,如何利用命名管道(NamedPipe)进行父子进程之间的通信,实现心跳检测功能。服务端创建并监听管道,客户端连接管道发送和接收消息。主要涉及ConnectNamedPipe、ReadFile、WriteFile等API的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

调试出来了,准备用于父子进程之间的心跳,记录一下

服务端

#if 1
#include <Windows.h>
#include <stdio.h>
#include <strsafe.h>

#define BUFSIZE 128

#define INSTANCES 8

#define PIPE_NAME "\\\\.\\pipe\\mynamedpipe"

#define PIPE_TIMEOUT 5000

#define PIPE_MSG_SRV "hi, clinet, i'm server."
#define PIPE_MSG_CLI "hi, server, i'm client."

typedef struct {
    OVERLAPPED oOlp;
    HANDLE hPipe;
    DWORD cbRet;

    DWORD dwRead;
    CHAR chRead[BUFSIZE];

    DWORD dwWrite;
    CHAR chWrite[BUFSIZE];

    DWORD dwState;
    BOOL bIsPending;
} PIPEINST;

enum 
{
    CONNECTING_STATE = 0,
    READING_STATE,
    WRITING_STATE
};


DWORD dwPipeCnt;

static PIPEINST Pipe[INSTANCES];
static HANDLE hEvents[INSTANCES];


BOOL PipeConnect(int idx)
{
    BOOL bOk;
    BOOL bisPending = FALSE;

    bOk = ConnectNamedPipe(Pipe[idx].hPipe, &Pipe[idx].oOlp);
    if (bOk)
        return FALSE;

    switch (GetLastError())
    {
    case ERROR_IO_PENDING:
        bisPending = TRUE;
        break;

    case ERROR_PIPE_CONNECTED:
        if (SetEvent(Pipe[idx].oOlp.hEvent))
            break;

    default:
    {
        return 0;
    }
    }

    return bisPending;
}

VOID PipeReconnect(DWORD i)
{
    if (!DisconnectNamedPipe(Pipe[i].hPipe))
        printf("DisconnectNamedPipe failed with %d.\n", GetLastError());

    Pipe[i].bIsPending = PipeConnect(i);
    Pipe[i].dwState = Pipe[i].bIsPending ? CONNECTING_STATE : READING_STATE;  
}

INT PipeCreate()
{
    INT idx = dwPipeCnt++;
    HANDLE hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
    if (hEvent == NULL)
        return -1;

    Pipe[idx].oOlp.hEvent = hEvents[idx] = hEvent;
    Pipe[idx].hPipe = CreateNamedPipeA(PIPE_NAME, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
        PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, INSTANCES, BUFSIZE, BUFSIZE,
        PIPE_TIMEOUT, NULL);

    if (Pipe[idx].hPipe == INVALID_HANDLE_VALUE)
        return -2;

    Pipe[idx].bIsPending = PipeConnect(idx);
    Pipe[idx].dwState = Pipe[idx].bIsPending ? CONNECTING_STATE : READING_STATE;
}

VOID PipeWait()
{
    DWORD dwWait, cbRet;
    INT idx;
    BOOL bOk;

    dwWait = WaitForMultipleObjects(dwPipeCnt, hEvents, FALSE, INFINITE);
    
    idx = dwWait - WAIT_OBJECT_0;
    if (idx < 0 || idx >= dwPipeCnt)
        return ;

    if (Pipe[idx].bIsPending) {
        bOk = GetOverlappedResult(Pipe[idx].hPipe, &Pipe[idx].oOlp, &cbRet, FALSE);
        printf("pending... %d %d %d\n", bOk, cbRet, GetLastError());

        switch (Pipe[idx].dwState)
        {
        case CONNECTING_STATE:
            if (!bOk)
                return ;
            Pipe[idx].dwState = READING_STATE;
            break ;

        case READING_STATE:
            if (!bOk || cbRet == 0) {
                PipeReconnect(idx);
                return ;
            }
            Pipe[idx].dwRead = cbRet;
            break;

        case WRITING_STATE:
            if (!bOk || cbRet != Pipe[idx].dwWrite) {
                PipeReconnect(idx);
                return ;
            }
            Pipe[idx].dwState = READING_STATE;
            break;

        default:
            return ;
        }
    }

    switch (Pipe[idx].dwState) {

    case READING_STATE:
        bOk = ReadFile(Pipe[idx].hPipe, Pipe[idx].chRead, BUFSIZE, &Pipe[idx].dwRead, &Pipe[idx].oOlp);
        if (!bOk && GetLastError() == ERROR_IO_PENDING)
            Pipe[idx].bIsPending = TRUE;
        else if (!bOk)
            PipeReconnect(idx);
        else {
            printf("recv: %s\n", Pipe[idx].chRead);
            Pipe[idx].bIsPending = FALSE;
            Pipe[idx].dwState = WRITING_STATE;
        }

        return;

    case WRITING_STATE:
        bOk = WriteFile(Pipe[idx].hPipe, PIPE_MSG_SRV, lstrlenA(PIPE_MSG_SRV), &cbRet, &Pipe[idx].oOlp);
        if (!bOk && GetLastError() == ERROR_IO_PENDING)
            Pipe[idx].bIsPending = TRUE;
        else if (!bOk)
            PipeReconnect(idx);
        else if (bOk && cbRet == lstrlenA(PIPE_MSG_SRV)) {
            printf("write msg: %s\n", PIPE_MSG_SRV);
            Pipe[idx].bIsPending = FALSE;
            Pipe[idx].dwState = READING_STATE;
        }
        else
            printf("err %d\n", GetLastError());

        break;

    default:
        break;
    }
}


int main()
{
    int idx = PipeCreate();
    PipeReconnect(idx);

    while (1) {
        PipeWait();
    }
}

#endif 

客户端

#if 1

#include <windows.h> 
#include <stdio.h>
#include <conio.h>
#include <tchar.h>

#define BUFSIZE 512

#define PIPE_CLI_MSG "hi, server, i'm cilnet."

#define PIPE_NAME "\\\\.\\pipe\\mynamedpipe"

char buf[256];

enum 
{
    PENDING,
    WRITE,
    READ
};

OVERLAPPED ov;

VOID PipeWait()
{
    static HANDLE hPipe = INVALID_HANDLE_VALUE;
    BOOL bOk;
    DWORD cbRead, cbWrite;
    DWORD dwMode;

    static DWORD dwFlag = PENDING;

    

    switch (dwFlag)
    {
    case PENDING:
        printf("for pending\n");
        if (hPipe != INVALID_HANDLE_VALUE) {
            dwFlag = WRITE;
            return;
        }

        hPipe = CreateFileA(PIPE_NAME, GENERIC_READ | GENERIC_WRITE , 0, NULL, 
            OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
        printf("wait pipe failed, error:%d\n", GetLastError());
        if (hPipe != INVALID_HANDLE_VALUE) {
            dwFlag = WRITE;
            return;
        }

        if (GetLastError() == ERROR_PIPE_BUSY)
            return;

        bOk = WaitNamedPipeA(PIPE_NAME, 200);
        if (!bOk) {
            printf("wait pipe failed, error:%d\n", GetLastError());
            return;
        }

    case WRITE:
        printf("for write\n");
        dwMode = PIPE_READMODE_MESSAGE;
        bOk = SetNamedPipeHandleState(hPipe, &dwMode, NULL, NULL);
        if (!bOk) {
            printf("err set pipe, error: %d\n", GetLastError());
            return;
        }

        bOk = WriteFile(hPipe, PIPE_CLI_MSG, lstrlenA(PIPE_CLI_MSG), &cbWrite, NULL);
        if (!bOk || cbWrite != lstrlenA(PIPE_CLI_MSG))
            break;

        printf("write msg %s\n", PIPE_CLI_MSG);
        dwFlag = READ;
        return ;

    case READ:
        printf("for read\n");
        do {

            bOk = ReadFile(hPipe, buf, 256, &cbRead, &ov);
            if (!bOk && GetLastError() == ERROR_IO_PENDING) {
                break;
            }

            if (!bOk && GetLastError() != ERROR_MORE_DATA) {
                break;
            }

            printf("read msg: %s\n", buf);

        } while (!bOk);

        dwFlag = WRITE;
        

    default:
        break;
    }

}

int main()
{

    ov.Offset = 0;
    ov.OffsetHigh = 0;
    ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

    while (1)
        PipeWait();
    
    return 0;

}

#endif
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值