在IOCP中发送数据的最佳方法是什么?

时间:2017-02-24 18:18:58

标签: c sockets winapi winsock iocp

调用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_progresstrue,那么我会显示一个消息框,告诉用户他现在无法发送任何内容,直到上一次发送操作完成为止。

现在我不认为这是处理IOCP中数据发送的好方法,因为用户会得到很多这样的消息框(特别是如果IOCP线程很忙而且需要一些时间来将is_sending_in_progress设置为false)。

那么是否有更好的方法来处理IOCP中的数据发送,例如为每个套接字设置多个WSAOVERLAPPED个实例,并在调用WSAOVERLAPPED时使用WSASend()实例?< / p>

3 个答案:

答案 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时,我们会在操作完成时调用回调(FileIOCompletionRoutineIoCompletionCallback - 当操作完成时,系统会自动调用此回调或如果你自己调用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请求。