c/s模型之命名管道

_拥你一生,如沐星辰_ _拥你一生,如沐星辰_     2022-09-23     143

关键词:

说明:利用管道实现服务端与客户端之间的交互。效果等同于利用socket。

命名管道(NamedPipe)是一种简单的进程间通信(IPC)机制,是服务器进程和一个或多个客户进程之间通信的单向或双向管道。
其本质是文件读写、内存共享。

采用命名管道完成进程通信的过程为:
1.在服务器端调用CreateNamedPipe创建命名管道之后,调用ConnectNamedPipe函数让服务器进程等待客户端进程连接到该命名管道的实例上。
2.在客户端,首先调用WaitNamedPipe函数判断当前是否有可以利用的命名管道实例,如果有就调用CreateFile函数打开该命名管道的实例,并建立一个连接。
之后就可以通过ReadFile、WriteFile进行通信。


函数讲解:
第一个CreateNamedPipe
函数功能:创建命名管道
函数原型:
HANDLEWINAPICreateNamedPipe(
LPCTSTRlpName,
DWORDdwOpenMode,
DWORDdwPipeMode,
DWORDnMaxInstances,
DWORDnOutBufferSize,
DWORDnInBufferSize,
DWORDnDefaultTimeOut,
LPSECURITY_ATTRIBUTESlpSecurityAttributes
);
参数说明:
第一个参数LPCTSTRlpName
表示管道名称,采用的形式是:\.pipepipename。最多可达256个字符的长度,而且不区分大小写。如果已经有同名管道,则会创建那个管道的一个新实例。

第二个参数DWORDdwOpenMode
表示管道的打开方式。下面列出最常用的三种,更多请参阅MSDN。
1.PIPE_ACCESS_DUPLEX
该管道是双向的,服务器和客户端进程都可以从管道读取或者向管道写入数据。
2.PIPE_ACCESS_INBOUND
该管道中数据是从客户端流向服务端,即客户端只能写,服务端只能读。
3.PIPE_ACCESS_OUTBOUND
该管道中数据是从服务端流向客户端,即客户端只能读,服务端只能写。

第三个参数DWORDdwPipeMode
表示管道的模式,下面是一些常用模式介绍,更多请参阅MSDN。
1.PIPE_TYPE_BYTE
数据作为一个连续的字节数据流写入管道。
2.PIPE_TYPE_MESSAGE
数据用数据块(名为“消息”或“报文”)的形式写入管道。
3.PIPE_READMODE_BYTE
数据以单独字节的形式从管道中读出。
4.PIPE_READMODE_MESSAGE
数据以名为“消息”的数据块形式从管道中读出(要求指定PIPE_TYPE_MESSAGE)。
5.PIPE_WAIT
同步操作在等待的时候挂起线程。
6.PIPE_NOWAIT
同步操作立即返回。

第四个参数DWORDnMaxInstances
表示该管道所能够创建的最大实例数量。必须是1到常数PIPE_UNLIMITED_INSTANCES间的一个值。
在WINBASE.H中有#define PIPE_UNLIMITED_INSTANCES 255

第五个参数DWORDnOutBufferSize
表示管道的输出缓冲区容量,为0表示使用默认大小。

第六个参数DWORDnInBufferSize
表示管道的输入缓冲区容量,为0表示使用默认大小。

第七个参数DWORDnDefaultTimeOut
表示管道的默认等待超时。

第八个参数LPSECURITY_ATTRIBUTESlpSecurityAttributes
表示管道的安全属性。
函数返回值:
函数执行成功返回命名管道的句柄,否则返回INVALID_HANDLE_VALUE。

第二个ConnectNamedPipe
函数功能:等待客户端连接命名管道
函数原型:
BOOLWINAPIConnectNamedPipe(
HANDLEhNamedPipe,
LPOVERLAPPEDlpOverlapped
);
函数说明:
第一个参数表示命名管道的句柄。
第二个参数是一个指向OVERLAPPED结构的指针,一般置为NULL就可以了。

第三个WaitNamedPipe
函数功能:客户端连接命名管道
函数原型:
BOOLWINAPIWaitNamedPipe(
LPCTSTRlpNamedPipeName,
DWORDnTimeOut
);
函数说明:
第一个参数LPCTSTRlpNamedPipeName
表示管道名称,采用的形式是:\servernamepipepipename。如果是本机管道,servername用“.”来表示。

第二个参数DWORDnTimeOut
表示等待命名管道的一个实例有效的超时时间,单位毫秒。也可以用NMPWAIT_USE_DEFAULT_WAIT表示使用命名管道的设定值(在调用CreateNamedPipe创建命名管道时指定的),NMPWAIT_WAIT_FOREVER表示无限等待。
函数返回值:
在指定时间内连接成功返回TRUE,否则返回FALSE。
注意
1:如果指定名称的命名管道还没创建,函数立即返回,返回值为FALSE。
2:如果函数执行成功返回TRUE,表示至少有一个命名管道的实例有效,接下来应该使用CreateFile函数打开命名管道的一个句柄,但是CreateFile可能会打开管道失败,因为该实例有可能被服务端关闭或被已经被其他客户端打开。

服务端和客户端的主要步骤如下所示:
1. 服务端用CreateNamedPipe创建一个命名管道并使用ConnectNamedPipe等待客户端的连接。
2. 客户端使用WaitNamedPipe连接成功后,用CreateFile打开管道并使用WriteFile向管道中写入一段数据(即向服务端发送消息)。
3. 服务端使用ReadFile从管道中读取数据后(即收到消息)再向管道中写入确认信息表明已经收到客户端传输的数据(即通知客户端已收到)。
4. 客户端收到确认信息后结束,调用CloseHandle关闭管道(该管道是CreateFile打开的)。
5.服务端使用DisconnectNamedPipe和CloseHandle关闭管道。

源代码:

//服务端


#include "stdafx.h"
#include <Windows.h>

int _tmain(int argc, _TCHAR* argv[])
{
    const char *szPipeName = "\\.\pipe\Pipe";
    //创建命名管道
    HANDLE hPipe = CreateNamedPipe(
        szPipeName,             // pipe name 
        PIPE_ACCESS_DUPLEX | 
        FILE_FLAG_OVERLAPPED,       // read/write access 
        PIPE_TYPE_MESSAGE |       // message type pipe 
        PIPE_READMODE_MESSAGE |   // message-read mode 
        PIPE_WAIT,                // blocking mode 
        PIPE_UNLIMITED_INSTANCES, // max. instances  
        MAXBYTE,                  // output buffer size 
        MAXBYTE,                  // input buffer size 
        0,                        // client time-out 
        NULL);                    // default security attribute 

    if (hPipe == INVALID_HANDLE_VALUE)
    {
        printf("CreateNamedPipe Error :%d", GetLastError());
    }

    char pRecvBuf[MAXBYTE] = { 0 };
    DWORD dwLen=0;

    //连接管道
    if (ConnectNamedPipe(hPipe, NULL))
    {
        printf("连接成功,开始接收数据!
");
        while (true)
        {
            //取得客户端的数据
            if (ReadFile(hPipe, pRecvBuf, MAXBYTE, &dwLen, 0))
            {
                printf("%s
", pRecvBuf);
            }

            if (strcmp(pRecvBuf, "exit") == 0)
            {
                break;
            }

            //将收到的数据进行返回
            if (WriteFile(hPipe, pRecvBuf, strlen(pRecvBuf) + sizeof(char), &dwLen, 0))
            {
                
            }
            else
            {
                break;
            }
        }
    }
    // 关闭管道
    DisconnectNamedPipe(hPipe);
    CloseHandle(hPipe);
    return 0;
}

 

//客户端

#include "stdafx.h"
#include <Windows.h>

int _tmain(int argc, _TCHAR* argv[])
{
    const char *szPipeName = "\\.\pipe\Pipe";
    //检测是否存在该命名管道
    if (WaitNamedPipe(szPipeName, NMPWAIT_WAIT_FOREVER) == TRUE)
    {
        printf("连接命名管道成功!
");
    }

    //打开文件--连接管道
    HANDLE hFile = CreateFile(szPipeName, GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

        char pSendBuf[MAXBYTE] = { 0 };
        char pRecvBuf[MAXBYTE] = {0};
        DWORD dwLen = 0;
        
        while (true)
        {
            gets_s(pSendBuf);
            //将管道传数据
            if(!WriteFile(hFile, pSendBuf, strlen(pSendBuf) + sizeof(char), &dwLen, NULL))
            {
                printf("False
");
            }
            if (strcmp(pSendBuf, "exit") == 0)
            {
                break;
            }
            //读取管道中的数据
            if (ReadFile(hFile, pRecvBuf, MAXBYTE, &dwLen, 0))
            {
                printf("return :%s 
", pRecvBuf);
            }
            
        }
    
    //关闭管道
    CloseHandle(hFile);
    return 0;
}

 

windows命名管道

  命名管道是通过网络来完成进程间的通信,它屏蔽了底层的网络协议细节。  将命名管道作为一种网络编程方案时,它实际上建立了一个C/S通信体系,并在其中可靠的传输数据。命名管道服务器和客户机的区别在于:服务... 查看详情

windows命名管道

命名管道是通过网络来完成进程间的通信,它屏蔽了底层的网络协议细节。  将命名管道作为一种网络编程方案时,它实际上建立了一个C/S通信体系,并在其中可靠的传输数据。命名管道服务器和客户机的区别在于:服务器是... 查看详情

进程间通信之命名管道

命名管道(FIFO)是进程间通信的一种方式,DEMO如下://写进程intmain(intargc,char**argv){charfilename[]="/tmp/my_fifo";if(mkfifo(filename,0777)<0){perror("mkfifoerror");exit(1);}intfd=open(filename,O_WRONLY);charbuffer[128]= 查看详情

进程间通信--fifo(命名管道)

...路径名与之关联,以FIFO的文件形式存储到文件系统中。命名管道是一个设备文件,因此进程间不需要亲缘关系,只要可以访问与之关联的路径即可,就能同FIFO通信命名管道通过mkfifo命名一个管道,然后通过openreadwrite进行文件读... 查看详情

进程间通信之管道(代码片段)

...四种情况        1.1.6匿名管道的特征        1.2命名管道     1.2.1命名管道的原理     1.2.2创建命名管道      查看详情

linux进程间通信之管道(pipe)命名管道(fifo)与信号(signal)

 整理自网络UnixIPC包括:管道(pipe)、命名管道(FIFO)与信号(Signal) 管道(pipe)管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通... 查看详情

c/s模型之tcp协议

服务端://WSASever.cpp:定义控制台应用程序的入口点。//#include"stdafx.h"#include<WinSock2.h>#include<Windows.h>#pragmacomment(lib,"wSock32.lib")int_tmain(intargc,_TCHAR*argv[]){WORDwVersionRequested;WSADATAw 查看详情

linux之进程间通信——管道

...解匿名管道管道的读写规则 情景1情景2 情景3​ 情景4命名管道创建命名管道命令行方式创建函数创建命名管道的应用场景 场景1 场景2场景3进程间是怎么通信的之前我们说过,进程与进程之间是相互独立的,它们的数... 查看详情

进程间通信——命名管道

...是没有名字,因此只能用于具有亲缘关系的进程间通信,命名管道(namedpipe或FIFO)解决了这一问题。FIFO提供一个路径名与之关联,以FIFO文件的形式存储于文件系统中。文件系统中路径名是全局的,各进程都可以访问,因此可以... 查看详情

c/s模型之udp协议

 说明:利用UDP协议,创建一个服务器和一个客户端。两者间进行通信。由客户端进行输入内容,而服务器将接受的内容进行再一次返回,并显示在服务端。//UDP_Seversock.cpp:定义控制台应用程序的入口点。#include"stdafx.h"#include&l... 查看详情

c/s模型之tcp群聊

说明:利用TCP协议和多线程实现群聊功能。一个服务器,多个客户端(同一个程序多次启动)。客户端向服务端发送数据,由服务端进行转发到其他客户端。/服务端//WSASever.cpp:定义控制台应用程序的入口点。//#include"stdafx.h"#inclu... 查看详情

非阻塞命名管道

】非阻塞命名管道【英文标题】:Non-blockingnamedpipes【发布时间】:2011-03-1519:44:55【问题描述】:问题摘要:我已经设法大大加快了上传图片时的翻阅速度,但代价是使用并发性。现在我需要针对竞争条件保护该并发性。我打算... 查看详情

命名管道中的 C# 死锁

...心收到了死锁:(逻辑如下。有命名管道。客户端和服务器模型。在服务器部分有一个循环,它总是ping命名管道并处理客户端发送的内容,有时会发回响应。在我管道的客户端,我有来自其他开发人员的以下方法,用于向服务器发... 查看详情

.netcorehttpclient使用之消息管道解析(代码片段)

...geHandler的使用场景和区别二、源代码阅读2.1核心消息管道模型图先贴上一张核心MessageHandler管道模型的流程图,图如下:HttpClient中的 查看详情

.netcorehttpclient使用之消息管道解析(代码片段)

...geHandler的使用场景和区别二、源代码阅读2.1核心消息管道模型图先贴上一张核心MessageHandler管道模型的流程图,图如下:HttpClient中的 查看详情

ipc-命名管道(fifo)-使用(代码片段)

命名管道-FIFO命名管道函数原型注意事项FIFO出错信息简单应用参考资料命名管道我们前面介绍了匿名管道(pipe),匿名管道实际上就是:内存上的一块缓存。它的主要实现方式是借助于fork之后父进程和子进程会... 查看详情

[linux]进程间通信之共享内存

...们了解了通过管道完成进程间通信,我们了解匿名管道和命名管道,并且通过编码模拟实现使用了匿名管道和命名管道。我们知道要让进程间完成通信必须让这两个进程首先看到同一份资源,因此给予这个前提,本篇博文我们了... 查看详情

命名管道:服务器端如何知道客户端已断开连接?

】命名管道:服务器端如何知道客户端已断开连接?【英文标题】:Namedpipes:howserversidecanknowthatclienthasdisconnected?【发布时间】:2012-02-0116:55:22【问题描述】:我有2个应用程序使用命名管道进行通信。主程序调用客户端程序并创... 查看详情