管道包括三种:
1):普通管道PIPE,通常有很多限制,一是半双工,只能单向传输,二是只能在父子进程间使用
2):流管道:这种能双向传输,但是也是只能父子进程间使用。
3):命名管道,去除了以上的第二种限制,可以在许多不相关的进程间进行通讯。也是半双工的通信方式。
通常我们把管道分为匿名管道和命名管道。但对于匿名管道的话,只能在本机上进程之间通信,而且只能实现本地的父子进程之间的通信,局限性太大了。命名管道,就和匿名管道有些不同了,在功能上也就显得强大许多,至少其可以实现跨网络之间的进程的通信,同时其客户端既可以接收数据也可以发送数据,服务器端也是可以接收数据,又可以发送数据。
匿名管道的概述
对于匿名管道而言,命名管道使用了windows安全机制,因而命名管道的服务器端可以控制哪些客户有权与其建立连接。哪些客户端是不能够与这个命名管道建立连接的。命名管道的通信是以连接的方式进行的,服务器创建一个命名管道对象,然后在此对象上等待连接请求,一旦客户连接过来,则两者都可以通过命名管道读或者写数据。
命名管道提供了两种通信模式:字节模式和消息模式。在字节模式下,数据以一个连续的字节流的形式在客户机和服务器之间流动。而在消息模式下,客户机和服务器则通过一系列不连续的数据单位,进行数据的收发,每次在管道上发出一个消息后,它必须作为一个完整的消息读入。
命名管道的使用步骤
服务器端:
1):服务器进程调用CreateNamedPipe函数来创建一个有名称的命名管道在创建命名管道的时候必须指定一个本地的命名管道名称。windows允许同一个本地的命名管道名称右多个命名管道实例。所以,服务器进程在调用CreateNamedPipe函数时必须指定最大允许的实例数(0-255).如果CreateNamedPipe函数成功返回后,服务器进程得到一个指向一个命名管道实例的句柄。
2):服务器进程就可以调用ConnectNamedPipe来等待客户的连接请求,这个ConnectNamedPipe既支持同步形式,又支持异步形式,若服务器进程以同步形式调用 ConnectNamedPipe函数,如果没有得到客户端的连接请求,则会一直等到客户端的连接请求。当该函数返回时,客户端和服务器之间的命名管道连接已经建立起来了。
3):这个时候服务器端就可以向客户端读(ReadFile)/写(WriteFile)数据了。
4):在已经建立连接的命名管道实例中,服务器进程就会得到一个指向该管道实例的句柄,这个句柄称之为服务器端句柄,同时服务端进程可以调用DisconnectNamedPipe函数,将一个管道实例与当前建立连接的客户端进程断开,从而可以重新连接到新的客户端进程。当然,服务器也可以调用CloseHandle来关闭一个已经建立连接的命名管道实例。
客户端:
1):客户端进程调用CreateFile函数连接到一个正在等待连接的命名管道上。在这里客户端需要指定将要连接的命名管道上。当CreateFile成功返回之后,客户端就得到了一个指向已经建立连接的命名管道实例的句柄。在这里客户端也可以先调用WaitNamedPipe函数来测试指定名称的管道实例是否可用。在已经建立的命名管道实例中,客户端进程就会得到一个指向该管道实例的句柄。这个句柄称之为客户端句柄。
2):这个时候客户端就可以向服务器读(ReadFile)/写(WriteFile)数据了.
3):客户端可以调用CloseHandle来关闭一个已经建立连接的命名管道实例。
CreateNamedPipe:
1 //创建命名管道的函数的使用
2 CreateNamedPipe("\\.\Pipe\Test",PIPE_ACCESS_DUPLEX,PIPE_NOWAIT,10,1024,1024,100,NULL)
3 1、为创建的管道命名
4 2、指定管道的访问方式、重叠方式、写直通方式以及管道句柄的安全访问方式(PIPE_ACCESS_DUPLEX这里指双向模式)
5 3、指定管道句柄的类型、读取和等待方式(PIPE_NOWAIT指允许非阻塞方式)
6 4、指定管道能够创建的实例的最大数目
7 5、指定为输出缓冲区所保留的字节数
8 6、指定为输入缓冲区所保留的字节数
9 7、指定默认超时时间,单位ms,同一管道的不同实例指定值需要相同
10 8、指向SECURITY_ATTRIBUTES结构的指针,该结构指定了命名管道的安全描述符
该函数用来创建一个命名管道的实例,并返回这个命名管道的句柄。如果需要创建一个命名管道的多个实例,就需要多次调用CreateNamedPipe函数,参数 lpName 为一个字符串,其格式必须为 \.pipepipeName,其中圆点 ”.” 表示的是本地机器,如果想要与远程的服务器建立连接,那么这个圆点位置处应指定这个远程服务器的名称,而其中的 “pipe” 这个是个固定的字符串,也就是说不能进行改变的,最后的 “pipename” 则代表的是我将要创建的命名管道的名称了,参数 dwOpenMode 用来指定管道的访问方式,重叠方式,写直通方式,还有管道句柄的安全访问方式。
ConnectNamedPipe:
1 //服务器等待客户端的连接请求的到来(并非连接服务器端的命名管道!)
2 ConnectNamedPipe(hPipe, NULL)
3 1、指向一个命名管道实例的服务器的句柄,该句柄由CreateNamedPipe函数返回
4 2、指向OVERLAPPED结构体的指针,默认为NULL,表明使用默认的同步IO方式
接收客户端发送数据ReadFile & 向客户端发送数据WriteFile:
1 //文件的写入
2 WriteFile(hPipe, strMessage, sizeof(strMessage), &wLen, 0)
3
4 1、指定要写入数据的文件的句柄
5 2、指向包含将要将要写入文件的数据的缓冲区的指针
6 3、指明要向文件中写入的字节数
7 4、用来接收实际写入到文件中的字节数
8 5、指向OVERLAPPED结构体的指针,默认为NULL,表明使用默认的同步IO方式
//文件的读取
1 ReadFile(hPipe, buf, 256, &rLen, NULL)
2 1、指定要读取数据的文件的句柄
3 2、指向包含将要将要接收的文件中读取数据的缓冲区的指针
4 3、指明要向文件中读取的字节数
5 4、用来接收实际读取到的字节数
6 5、指向OVERLAPPED结构体的指针,默认为NULL,表明使用默认的同步IO方式
CloseHandle:
CloseHandle(hPipe); //关闭管道句柄
客户端单独用到的两个函数
WaitNamedPipe:
1 WaitNamedPipe(TEXT("\\.\Pipe\pipeTest"), NMPWAIT_WAIT_FOREVER)
2 1、指定命名管道的名称
3 2、指定超时间隔,NMPWAIT_WAIT_FOREVER表示一直等待,直到出现了一个可用的命名管道的实例
CreateFile:
CreateFile("\\.\Pipe\Test",GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
1、指定用于创建或打开的对象的名称
2、指定对象的访问方式,GENERIC_WRITE表示指定对象具有写访问
3、指定共享方式,如果此参数为0,表示对象不能被共享
4、指向SECURITY_ATTRIBUTES结构的指针,该结构指定了命名管道的安全描述符,如果没有特殊的需求,默认值为NULL
5、指定如何创建文件(OPEN_EXISTING表示打开文件,如果文件不存在,则函数调用失败)
6、设置文件属性和标志(FILE_ATTRIBUTE_NORMAL表示该文件没有其他属性设置)
7、指定具有GENERIC_READ访问方式的模板文件的句柄