IOCP 文档解释问题 - 缓冲区所有权歧义
因为我不是以英语为母语的人,所以我可能会错过一些东西,所以也许这里有人比我更了解。
摘自 WSASend 在 MSDN 上的文档:
lpBuffers[输入]
指向 WSABUF 数组的指针 结构。每个WSABUF结构 包含一个指向缓冲区的指针和 缓冲区的长度(以字节为单位)。对于一个 Winsock应用程序,一旦WSASend 函数被调用,系统拥有 这些缓冲区和应用程序可能 无法访问它们。该数组必须 在有效期内保持有效 发送操作。
好的,你能看到粗体文字吗?这就是不明白的地方!
我可以想到这句话的两种翻译(可能是别的东西,你能想到的):
翻译 1 - “缓冲区”指的是我在调用该函数时传递的 OVERLAPPED 结构。仅当收到有关该对象的完成通知时,我才可以再次重用该对象。
翻译 2 - “缓冲区”指的是实际缓冲区,即包含我正在发送的数据的缓冲区。如果 WSABUF 对象指向一个缓冲区,那么在操作完成之前我无法触及该缓冲区。
谁能告诉这句话的正确解释是什么?
还有......如果答案是第二个 - 你会如何解决它?
因为对我来说,这意味着对于我发送的每个数据/缓冲区,我必须在发送方保留它的副本 - 因此在高流量应用程序上有许多“待处理”缓冲区(不同大小),这确实会发生损害“可扩展性”。
声明 1:
除了上面的段落(“和...”)之外,我认为 IOCP 会将要发送的数据复制到它自己的缓冲区并从那里发送,除非您设置 SO_SNDBUF 为零。
声明 2:
我在函数体中使用堆栈分配的缓冲区(你知道,类似于 char cBuff[1024]; - 如果对主要问题的翻译是第二个选项(即缓冲区必须保持原样,直到发送已完成),那么...这真的把事情搞砸了!你能想出一种方法来解决它吗?(我知道,我在上面问过它)。
Since I'm not a native English speaker I might be missing something so maybe someone here knows better than me.
Taken from WSASend's doumentation at MSDN:
lpBuffers [in]
A pointer to an array of WSABUF
structures. Each WSABUF structure
contains a pointer to a buffer and the
length, in bytes, of the buffer. For a
Winsock application, once the WSASend
function is called, the system owns
these buffers and the application may
not access them. This array must
remain valid for the duration of the
send operation.
Ok, can you see the bold text? That's the unclear spot!
I can think of two translations for this line (might be something else, you name it):
Translation 1 - "buffers" refers to the OVERLAPPED structure that I pass this function when calling it. I may reuse the object again only when getting a completion notification about it.
Translation 2 - "buffers" refer to the actual buffers, those with the data I'm sending. If the WSABUF object points to one buffer, then I cannot touch this buffer until the operation is complete.
Can anyone tell what's the right interpretation to that line?
And..... If the answer is the second one - how would you resolve it?
Because to me it implies that for each and every data/buffer I'm sending I must retain a copy of it at the sender side - thus having MANY "pending" buffers (in different sizes) on an high traffic application, which really going to hurt "scalability".
Statement 1:
In addition to the above paragraph (the "And...."), I thought that IOCP copies the data to-be-sent to it's own buffer and sends from there, unless you set SO_SNDBUF to zero.
Statement 2:
I use stack-allocated buffers (you know, something like char cBuff[1024];
at the function body - if the translation to the main question is the second option (i.e buffers must stay as they are until the send is complete), then... that really screws things up big-time! Can you think of a way to resolve it? (I know, I asked it in other words above).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
答案是,在操作完成之前,重叠结构和数据缓冲区本身无法重用或释放。
这是因为操作是异步完成的,因此即使数据最终被复制到 TCP/IP 堆栈中操作系统拥有的缓冲区中,也可能要等到将来某个时间才会发生,并且您会收到写入完成发生的通知。请注意,如果您在没有显式流量控制的情况下发送并依赖 TCP 堆栈为您进行流量控制,那么在写入完成时,这些可能会延迟令人惊讶的时间(请参见此处:使用 WSASend 的一些重叠未使用 GetQueuedCompletionStatus 及时返回? ) ...
你不能使用堆栈分配的缓冲区,除非你将一个事件放置在重叠结构中并阻塞它直到异步操作完成;这样做没有多大意义,因为你会比正常的阻塞调用增加复杂性,并且通过发出异步调用然后等待它也不会获得很多好处。
在我的 IOCP 服务器框架中(您可以从此处免费获取该框架) 我使用动态分配的缓冲区,其中包括重叠结构并且是引用计数的。这意味着当完成发生并且引用被释放时,就会发生清理(在我的例子中,它们被返回到池中以供重用)。这也意味着您可以选择在操作后继续使用缓冲区,并且清理仍然很简单。
另请参阅此处:我/ O 完成端口,如何释放每个套接字上下文和每个 I/O 上下文?
The answer is that the overlapped structure and the data buffer itself cannot be reused or released until the completion for the operation occurs.
This is because the operation is completed asynchronously so even if the data is eventually copied into operating system owned buffers in the TCP/IP stack that may not occur until some time in the future and you're notified of when by the write completion occurring. Note that with write completions these may be delayed for a surprising amount of time if you're sending without explicit flow control and relying on the the TCP stack to do flow control for you (see here: some OVERLAPS using WSASend not returning in a timely manner using GetQueuedCompletionStatus?) ...
You can't use stack allocated buffers unless you place an event in the overlapped structure and block on it until the async operation completes; there's not a lot of point in doing that as you add complexity over a normal blocking call and you don't gain a great deal by issuing the call async and then waiting on it.
In my IOCP server framework (which you can get for free from here) I use dynamically allocated buffers which include the OVERLAPPED structure and which are reference counted. This means that the cleanup (in my case they're returned to a pool for reuse) happens when the completion occurs and the reference is released. It also means that you can choose to continue to use the buffer after the operation and the cleanup is still simple.
See also here: I/O Completion Port, How to free Per Socket Context and Per I/O Context?