使用重叠命名管道的服务器:如何将 GetOverlappedResult() 与 ReadFile() 一起使用?
我编写了一个使用重叠命名管道的服务器和客户端。我的问题主要是 Readfile() 和 GetOverlappedResult()。
请注意,该程序是测试代码。稍后它将集成到一个框架中(我将Linux代码移植到使用AF_UNIX地址系列进行套接字连接的unix)
我描述了服务器部分。我有 2 个线程:
1)主线程打开一个重叠的命名管道,然后循环 WaitForMultipleObjects()。 WaitForMultipleObjects() 等待 3 个事件:第一个事件等待客户端连接。第二个允许我干净地退出程序。当 ReadFile() 中的操作待处理时,会发出第三个信号。
2) 当客户端连接时启动第二个线程。它循环遍历 ReadFile()。
这是服务器代码:
我主要使用MSDN文档(命名管道服务器使用重叠 I/O、命名管道客户端)、SDK 和互联网上的其他文档来编写该代码。在 [1] 中查找客户端代码。客户端代码需要一些关爱,但现在,我专注于使服务器完美运行。
服务器代码中有 4 个函数(我忘记了显示错误消息的函数):
a) svr_new:它创建重叠的命名管道和 3 个事件,并调用 ConnectNamedPipe()
b) svr_del 释放所有资源
c) _read_data_cb:调用 ReadFile() 的线程
d) main() 函数(主线程),它在 WaitForMultipleObjects() 上循环
我的目标是在 _read_data_cb() 中检测客户端何时断开连接(ReadFile() 失败并且 GetLastError() 返回 ERROR_BROKEN_PIPE )以及数据何时来自客户端。
我不明白的是:
- 我应该调用 GetOverlappedResult() 吗?
- 如果是,在哪里?当 ReadFile() 失败并且 GetLastError() 返回 ERROR_IO_PENDING (粘贴的第 50 行)时?当 WaitForMultipleObjects() 返回时(粘贴的第 303 行,我在那里评论了代码)?其他地方?
- 当 WaitForMultipleObjects() 返回时(粘贴的第 302 行),我对 ReadFile() 事件执行 ResetEvent。调用它的地方正确吗?
使用我粘贴的代码,如果客户端发送这 24 个字节(ReadFile() 缓冲区的大小为 5 个字节),则结果如下。我有意设置该值来测试如果客户端发送的数据大于 ReadFile( )缓冲区)
消息:“致敬,这是客户!”
输出:
$ ./server.exe 等待客户... 等待多个对象:0 客户端已连接 (1) 等待多个对象:2 * 读取文件:5 等待多个对象:2 * 读取文件:5 等待多个对象:2 * 读取文件:5 等待多个对象:2 * 读取文件:5 等待多个对象:2 * ReadFile : 4
注意:WaitForMultipleObjects() 的调用次数少于该值,看起来是随机的。
所以,在我的代码中,我没有调用 getOverlappedResult(),ReadFile() 成功(il 读取 5*4 + 4 = 24 字节),但我不知道读取操作何时完成。
注意:当ReadFile()因ERROR_IO_PENDING失败时,我添加了一个printf(),即无限期地调用printf()。
另外,客户端发送2条消息。上面一张,三秒后又一张。第二条消息永远不会被读取,并且 ReadFile() 失败并出现错误 ERROR_SUCCESS... (准确地说,ReadFile() 返回 FALSE 并且 GetLastError() 返回 ERROR_SUCCESS)
所以,我完全迷失了。我在 Internet、MSDN、SDK 代码(Server32.c 和 Client32.c)中搜索了几个小时。我仍然不知道针对我的具体情况该怎么办。
那么,有人解释一下如何使用 GetOverlappedResult() (如果我必须使用它)来了解如何检查读取操作是否完成以及在哪里完成?甚至,如果有人可以修复我的代码:-)我给出了代码,以便每个人都可以测试它(我在互联网上找到了很多文档,但它几乎总是不精确:-/)
谢谢
I have written a server and a client that are using an overlapped named pipe. My problem is mainly with Readfile() and GetOverlappedResult().
Note that this program is a test code. It will be integrated later in a framework (I'm porting linux code to unix that uses AF_UNIX adress family for socket connections)
I describe the server part. I have 2 threads :
1) the main thread opens an overlapped named pipe, then loop over WaitForMultipleObjects(). WaitForMultipleObjects() waits for 3 events: the 1st one waits for a client to connect. The 2nd allows me to cleanly quit the program. The 3rd is signaled when an operation is pending in ReadFile().
2) The second thread is launched when the client is connected. It loops over ReadFile().
Here is the server code:
I mainly used MSDN doc (named pipe server using overlapped I/O, named pipe client), the SDK, and other doc on internet, to write that code. Look in [1] for the client code. The client code needs some love, but for now, I focus on making the server working perfectly.
There are 4 functions in the server code (i forget the function that display error messages):
a) svr_new: it creates the overlapped named pipe and the 3 events, and calls ConnectNamedPipe()
b) svr_del frees all the resources
c) _read_data_cb: the thread that calls ReadFile()
d) the main() function (the main thread), which loops over WaitForMultipleObjects()
My aim is to detect in _read_data_cb() when the client disconnects (ReadFile() fails and GetLastError() returns ERROR_BROKEN_PIPE) and when data comes from the client.
What I don't understand:
- Should I call GetOverlappedResult() ?
- If yes, where ? When ReadFile() fails and GetLastError() returns ERROR_IO_PENDING (line 50 of the paste) ? When WaitForMultipleObjects() returns (line 303 of the paste, I commented the code there) ? Somewhere else ?
- I do a ResetEvent of the event of ReadFile() when WaitForMultipleObjects() returns (line 302 of the paste). Is it the correct place to call it ?
With the code I pasted, here is the result if the client sends these 24 bytes (the ReadFile() buffer is of size 5 bytes. I intentionnaly set that value to test what to do if a client sends some data larger than the ReadFile() buffer)
message : "salut, c'est le client !"
output:
$ ./server.exe
waiting for client...
WaitForMultipleObjects : 0
client connected (1)
WaitForMultipleObjects : 2
* ReadFile : 5
WaitForMultipleObjects : 2
* ReadFile : 5
WaitForMultipleObjects : 2
* ReadFile : 5
WaitForMultipleObjects : 2
* ReadFile : 5
WaitForMultipleObjects : 2
* ReadFile : 4
Note: WaitForMultipleObjects() can be called less than that, it seems random.
So, in my code, I do not call getOverlappedResult(), ReadFile() succeeds (il reads 5*4 + 4 = 24 bytes), but I don't know when the read operation has finished.
Note: I I add a printf() when ReadFile() fails with ERROR_IO_PENDING, that printf() is called indefinitely.
In addition, the client sends 2 messages. The one above, and another one 3seconds later. The 2nd message is never read and ReadFile() fails with the error ERROR_SUCCESS... (so to be precise, ReadFile() returns FALSE and GetLastError() returns ERROR_SUCCESS)
So, I'm completely lost. I have searched hours on Internet, in MSDN, in the SDK code (Server32.c and Client32.c). I still do not know what to do in my specific case.
So, ca someone explain me how to use GetOverlappedResult() (if I have to use it) to know how to check if the read operation finished, and where ? And even, if someone can fix my code :-) I gave the code so that everyone can test it (i find a lot of doc on internet, but it is almost always not precise at all :-/ )
thank you
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
查看 I/O 完成端口。在我看来,这是接收和处理有关 Windows 中重叠操作的通知的最有效方法。因此,基本上,当您准备好处理新的完成事件时,您需要在阻塞和非阻塞模式下使用 GetQueuedCompletionStatus 和 GetQueuedCompletionStatusEx,而不是时不时地调用 GetOverlappedResult。事实上,您甚至可以完全摆脱 WaitForMultipleObjects。
另外,您的目标是哪种类型的 Unix?在 Solaris 中有一个非常相似的抽象。查看 man port_create。
不幸的是,Linux 中没有类似的东西。信号(包括实时信号)在某种程度上可以用作可等待完成对象,但它们不如 Windows 和 Solaris 中的端口那么全面。
Take a look at I/O Completion Ports. In my opinion it's the most efficient way to receive and handle notifications about overlapped operations in Windows. So basically you will need to use GetQueuedCompletionStatus and GetQueuedCompletionStatusEx in blocking and non-blocking mode when you're ready to process new completion events, instead of calling GetOverlappedResult from time to time. As a matter of fact, you can even get rid of WaitForMultipleObjects completely.
Also, which flavor of Unix are you targeting? In Solaris there's a very similar abstraction. Check out man port_create.
Unfortunately, there's nothing similar in Linux. Signals (including real-time) can be used to some extent as waitable completion objects, but they are not as comprehensive as the ports in Windows and Solaris.