我就是想实现,客户端连接上后,无论客户端发送多少数据我都可以存下来,比如发送1G的数据,但我网上找到的例子都是两端约定发送多长字节,不知道有没有办法实现?我的服务端代码如下:
#include "stdafx.h" #include <iostream> #include <windows.h> #include <ctime> using namespace std; #define BUFSIZE 5 void start(string pipeName) { BOOL fSuccess = false; char buffer[BUFSIZE]; DWORD len = 0; string result = ""; HANDLE hPipe = CreateNamedPipe(pipeName.c_str(),PIPE_ACCESS_DUPLEX,PIPE_TYPE_MESSAGE|PIPE_READMODE_MESSAGE|PIPE_WAIT ,PIPE_UNLIMITED_INSTANCES,0,0,NMPWAIT_WAIT_FOREVER,0); //waiting to be connected if(ConnectNamedPipe(hPipe, NULL) == NULL) return; len = 0; do { fSuccess = ReadFile(hPipe ,buffer ,BUFSIZE*sizeof(char) ,&len ,NULL); cout<<buffer; if ( ! fSuccess && GetLastError() != ERROR_MORE_DATA ) break; } while(fSuccess); cout<<"read completed."; CloseHandle(hPipe); } int main(int argc, char* argv[]) { start("\\\\.\\Pipe\\mypipe"); int c = getchar(); return 0; }
上面的代码中我虽然设置了BUFSIZE=5,但如果客户端发送过来的数据长度为8,它第一次循环中buffer接收到的数据长度竟然大于5,buffer[5]中装了5个有效字符,后面几个乱码字符,转换成string也确实有乱码,前5位正常,后几位是乱码。每次调用ReadFile后len的值都为5,按我的理解第二次len的值应该是3才对,所以我根本没办法区分哪此才是有效数据。
如果要接收的数据大于1G,岂非要定义一个大于1G的变量才能搞定吗? 主要是上面的循环如何把接收到的数据累加到result中,如何判断循环的终结等,c++中的字符串是我十几年来最搞不太懂的地方。
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365467(v=vs.85).aspx
If a named pipe is being read in message mode and the next message is longer than the nNumberOfBytesToRead parameter specifies, ReadFile returns FALSE and GetLastError returns ERROR_MORE_DATA. The remainder of the message can be read by a subsequent call to the ReadFile or PeekNamedPipefunction.
If the lpNumberOfBytesRead parameter is zero when ReadFile returns TRUE on a pipe, the other end of the pipe called the WriteFile function with nNumberOfBytesToWrite set to zero.
除此之外,关于如何使用协议切割数据流,可以参照 HTTP 协议的定义方式。
关于 C++ 中字符串的问题,char buffer[5],表示长度为 5 的字符数组,可以和 C# 中的长度为 5 的 byte 数组同等对待。如果你对 C# 中的 Encoding 比较熟悉的话,理解起来不是问题。
那比如我上面循环中的第一次循环中在接收到buffer[5]后, 我执行了 string str = string(buffer)后,str的长度大于5,它的前5位是有效的,后三位是乱码。
请问怎么能把buffer[5]转换成可输出的正确可靠的数据?
@沧海一杰: 我假定你是使用的 std::string 类型,那么它其中一个构造函数的形参是:const char * _Ptr,那么你会发现这里有个问题,就是没有指定 _Ptr 指向的字符串的长度。这是很危险的操作,会造成缓冲区溢出。因为在这里,有个默认的约定,就是假设 _Ptr 是指向的以 '\0' 结束的字符串。那么 std::string 在构造的时候,会从 _Ptr 开始识别,直到遇到 '\0' 后,将前面的所有字符识别为一个字符串。
你可以在内存窗口中观察 buffer 变量的内容,你会发现几乎在所有情况下,buffer[6] 的值都不等于 '\0',因此你才会得到一个错误的字符串,正确的做法是,在你认为 buffer 里内容表示的是一个字符串时,你需要追加 '\0',如下:
char buff[6]={0};
memcpy(buff,buffer,5);
std::string str(buff);
也就是说容纳字符串的数组总是字符串长度加 1 的大小。
关于正确可靠的数据的问题,这和你调用双方的约定有关,也就是说你的 buffer 中存储的到底是以什么编码方式编码的字符串。
@Launcher: 我明白了,我原也是知道这些,但C++字符串类型经常多达十几种,char* char[] LPCSTR LPWCSTR string Cstring TChar 经常被弄晕。 我也发现了,刚才我接收时发现循环走了四次,是因为我的发送端计算发送数据长度的语句有问题,导致多发了两次无效数据导致。