The*_*bie 1 c++ winapi c++11 c++14
我知道以前已经有人问过这个问题,但我找不到答案,所以我发帖寻求帮助。
我有一个 DLL,一旦注入进程就会创建一个命名管道。管道将等待客户端连接,并将数据发送到客户端,直到客户端断开连接。
在客户端,它只会连接到管道并接收数据并使用这些数据执行操作。
我的问题是,我希望能够发送超过 1 种类型的数据,例如 float、int、string 等。如何将数据重建为正确的数据(float、int 字符串等)?
这是我为客户提供的代码:
HANDLE hPipe;
DWORD dwWritten;
char Buffer[1024];
hPipe = CreateFile(TEXT("\\\\.\\pipe\\Pipe"),
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
if (hPipe != INVALID_HANDLE_VALUE)
{
WriteFile(hPipe,
Buffer, //How do I put all the data into a buffer to send over to the client?
sizeof(Buffer), // = length of string + terminating '\0' !!!
&dwWritten,
NULL);
CloseHandle(hPipe);
}
Run Code Online (Sandbox Code Playgroud)
服务器 :
wcout << "Creating Pipe..." << endl;
HANDLE hPipe;
char buffer[1024];
DWORD dwRead;
hPipe = CreateNamedPipe(TEXT("\\\\.\\pipe\\Pipe"),
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, // FILE_FLAG_FIRST_PIPE_INSTANCE is not needed but forces CreateNamedPipe(..) to fail if the pipe already exists...
1,
1024 * 16,
1024 * 16,
NMPWAIT_USE_DEFAULT_WAIT,
NULL);
while (hPipe != INVALID_HANDLE_VALUE)
{
if (ConnectNamedPipe(hPipe, NULL) != FALSE) // wait for someone to connect to the pipe
{
while (ReadFile(hPipe, buffer, sizeof(buffer) - 1, &dwRead, NULL) != FALSE)
{
/* add terminating zero */
buffer[dwRead] = '\0';
/* do something with data in buffer */
printf("%s", buffer);
}
}
DisconnectNamedPipe(hPipe);
}
Run Code Online (Sandbox Code Playgroud)
我的问题是,我有一堆数据想一次性发送到客户端,其中可能包含 float、int、double 等。一旦我从服务器收集了所有数据,我想发送将其发送给客户端,并让客户端通过拆分数据来解析它,如下所示:
void split(const string& s, char c,
vector<string>& v) {
string::size_type i = 0;
string::size_type j = s.find(c);
while (j != string::npos) {
v.push_back(s.substr(i, j - i));
i = ++j;
j = s.find(c, j);
if (j == string::npos)
v.push_back(s.substr(i, s.length()));
}
}
Run Code Online (Sandbox Code Playgroud)
我有点迷失如何将所有数据发送给客户端并正确获取原始值?
您必须使用一个库将数据转换为可以通过套接字发送的数据。这就是所谓的序列化器!您还可以使用序列化程序来序列化为数据流,或者也可以在 GUI 或其他方式中序列化。要接收数据,您只需对其进行“反序列化”即可。
您可以找到很多序列化器库,例如:
自定义代码看起来像(伪代码!):
class Check
{
int i;
float f;
template<SERIALIZER_TYPE>
void Serialize( SERIALIZER_TYPE& ser )
{
ser & i & f;
}
};
int main()
{
Check c;
std::string s;
Socket socket( ip, port );
WriteSerializer ser(socket);
ser & c & s;
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,您无需自己编写任何内容来“了解”数据类型如何序列化。类/结构必须提供序列化器方法,因此它们也可以拆分为其本机数据类型。
编辑:添加了评论中的问题:
是否可以通过 [a] 命名管道将这些数据从我的 DLL 发送到 EXE,而不是保存文件?
取自cereal文档:
谷物具有出色的标准库支持以及二进制、XML 和 JSON 序列化器。如果您需要其他东西,谷物被编写为可以轻松扩展以添加自定义序列化存档或类型。
因此,一种选择是根据您的需求编写新界面。
但看一下示例代码:
void x()
{
std::ofstream file( "out.xml" );
cereal::XMLOutputArchive archive( file ); // depending on the archive type, data may be
// output to the stream as it is serialized, or
// only on destruction
archive( some_data, more_data, data_galore );
}
Run Code Online (Sandbox Code Playgroud)
如您所见,使用了 astd::ofstream作为输出。因此,您可以简单地使用ofstream为套接字打开的内容。
如何使用套接字连接 std::ostream 的答案如下: How can I create an 'ostream' from a socket?
但手工完成这项工作也很简单。您必须为套接字编写自己的缓冲区类并将其连接到ofstream. 我相信不超过十行代码!
因此,您现在可以通过套接字以 XML、Json 或其他形式传输变量和对象。
编辑:来自评论:是的,使用管道而不是套接字也将适用,iostream并且该技术完全相同并且基于实现周围的某些内容streambuf。
C++ 将输出流连接到输入流
我希望它在 Windows 上istream也能以同样的方式工作并且具有同样的ostream适应性。
我相信,以问答方式不适合更深入地了解完整解决方案的细节。因此,如果对连接某些内容还有其他疑问iostream,请开始一个新问题!