调用WSASend()
时,我必须将WSAOVERLAPPED
实例传递给它,在上一次WSAOVERLAPPED
操作完成之前,我无法重复使用此WSASend()
实例(即,当完成数据包被放置在完成端口时,并且当我解除此完成数据包时,我猜。)
基于这种理解,我的应用程序中每个套接字都有一个WSAOVERLAPPED
实例,我也有一个布尔变量(称为is_sending_in_progress
)。
现在让我们说我有一个按钮,当点击到另一边时会发送字符串"hello"
。
现在,当用户点击此按钮时,我会检查is_sending_in_progress
是否为false
,如果是false
,那么我会调用WSASend()
并且然后将is_sending_in_progress
设置为true,现在当我呼叫GetQueuedCompletionStatus()
以取消完成数据包时,我将is_sending_in_progress
设置为false
。如果用户点击按钮并且is_sending_in_progress
为true
,那么我会显示一个消息框,告诉用户他现在无法发送任何内容,直到上一次发送操作完成为止。
现在我不认为这是处理IOCP中数据发送的好方法,因为用户会得到很多这样的消息框(特别是如果IOCP线程很忙而且需要一些时间来将is_sending_in_progress
设置为false
)。
那么是否有更好的方法来处理IOCP中的数据发送,例如为每个套接字设置多个WSAOVERLAPPED
个实例,并在调用WSAOVERLAPPED
时使用WSASend()
实例?< / p>
答案 0 :(得分:1)
你完全错误理解IOCP
和异步I / O.
我有一个与我的每个套接字关联的WSAOVERLAPPED实例 应用
否!!! 强>
您可以拥有任何类/结构关联/封装的套接字句柄。但是对于每个I / O操作,您必须分配一些继承自OVERLAPPED
的另一个数据结构。但需要明确理解 - 这是每个操作的结构,但不是每个插槽。必须在I / O操作开始之前分配此实例。在I / O操作结束后立即销毁。
这种结构与IRP
有某种关系,并且具有相似的意义和生命。在这个结构中除了OVERLAPPED
之外你必须指向你的类实例,它是封装套接字,一些标记描述了什么是这个I / O操作 - 发送,接收,连接,断开等等。可能还有一些额外的数据 - 与操作有关
我也有一个布尔变量(名为is_sending_in_progress)。
再次否!!!
我们可以在同一个套接字上进行多次I / O操作。我们可以在同一个套接字上及时进行多次发送操作 - 当然,每个操作必须是唯一的OVERLAPPED
(您的自定义用户模式IRP
),但需要明确理解 - 仅OVERLAPPED
每个操作 - 套接字句柄所在的类实例 - 不得包含(继承自)OVERLAPPED
。我们可以同时发送和接收操作。接收和断开。
只有单一限制 - 接收操作在某个时间不能是多个(几个)。但这不是OVERLAPPED
限制 - 只要你一次得到2个数据包 - 你不知道哪个是先发送的,哪个是第二个 - 所以你丢失了数据顺序
真正的异步I / O为您提供了极大的自由和动力,但前提是您深入了解它。
有没有更好的方法来处理IOCP中的数据发送
当您使用IOCP
的异步I / O时,我们会在操作完成时调用回调(FileIOCompletionRoutine
或IoCompletionCallback
- 当操作完成时,系统会自动调用此回调或如果你自己调用GetQueuedCompletionStatus
- 你需要自己也调用这个回调函数。我们必须在这个回调函数中使用socket进行所有操作。如果我们需要发送大部分数据 - 我们可以在块上打破它。直接发送第一个块当发送完成时 - 调用回调 - 这里我们称之为发送下一个数据块... - 在上一次发送完成时准确发送下一个块。
答案 1 :(得分:0)
听起来你的问题不是IOCP,而是一般的缓冲策略。可能对您有帮助的工作流程如下:
// on button click
add_message_to_buffer();
if(!is_sending_in_progress)
{
is_sending_in_progress = true;
start_send();
}
// in your IOCP loop, on completion of send.
if(buffer_has_more_data)
{
start_send();
}
else
{
is_sending_in_progress = false;
}
答案 2 :(得分:0)
你在想这个。
在启动新的异步IO时,分配一个新的OVERLAPPED
结构,在IOCP中接收它,然后将其删除。
一种非常流行的方法是从OVERLAPPED
“继承”(尽管C提供 - 用另一个变量组合)并附加回调。当IOCP将OVERLAPPED
出列时,将回调调度到某个线程池并删除OVERLAPPED
。
你可能也不想使用原始的Win32,而是想在它上面找到一个抽象,比如boost.asio(C ++)。您可能还想使用比原始套接字更友好的用户,比如HTTP请求。