我应该读取前9个字节,其中应包括协议(protocol)和数据包的传入大小。

当完成端口返回9个字节时,哪个更好呢? (表现/良好做法或明智的选择)

  • 在套接字上发布另一个重叠的读取,这次与数据包的大小有关,以便它在下一次完成时接收它?
  • 使用阻塞套接字在例程内部读取整个数据包,然后发布另一个与9个字节的recv重叠的数据包?
  • 以大块读取(确定大小),例如-4096,并具有一个计数器来继续读取每个重叠的完成内容,直到读取数据为止(例如,它将完成12次,直到读取所有数据包为止)。
  • 最佳答案

    答案取决于您使用的基础架构。通常,最好的事情是什么都不做。我知道这听起来很奇怪,所以让我解释一下。当OS与NIC通讯时,它通常至少具有一对RX / TX环形缓冲区,如果是商用硬件,则很可能通过PCIe总线与设备通讯。在PCIe总线的顶部有一个DMA引擎,它使NIC可以在不使用CPU的情况下读写主机内存。换句话说,当NIC处于 Activity 状态时,它将始终以最小的CPU干预自行读取和写入数据包。当然,有很多细节,但是您通常可以认为在发生的驱动程序级别上-读写总是由NIC使用DMA执行的,无论您的应用程序是否读写任何内容。或不。现在,最重要的是有一个OS基础结构,它允许用户空间应用程序向NIC发送数据或从NIC接收数据。当您打开套接字时,操作系统将确定您的应用程序对哪种数据感兴趣,并将条目添加到与网络接口(interface)通信的应用程序列表中。发生这种情况时,应用程序开始接收放置在内核中某种应用程序队列中的数据。无论您是否调用读取都没有关系,数据放置在此处。放置数据后,将通知应用程序。内核中的通知机制各不相同,但是它们都有一个相似的想法-让应用程序知道数据可用于调用read()。一旦数据位于该“队列”中,应用程序就可以通过调用read()来进行拾取。阻塞读取和非阻塞读取之间的区别很简单-如果读取正在阻塞,内核将简单地暂停应用程序的执行,直到数据到达为止。在非阻塞读取的情况下,无论有无数据,该控件无论如何都将返回给应用程序。如果发生后者,则应用程序可以继续尝试(也可以在套接字上旋转),也可以等待内核发出的通知说数据可用,然后继续读取数据。现在让我们回到“什么都不做”。这意味着套接字被注册为仅接收一次通知。注册后,该应用程序无需执行任何操作,只需收到一条通知,指出“数据已存在”。因此,应用程序应该做的是侦听该通知,并仅在数据存在时执行读取。接收到足够的数据后,该应用可以以某种方式开始处理它。知道了所有这些之后,让我们看看这三种方法中有什么更好的...



    这是一个好方法。理想情况下,您不必“发布”任何东西,但这取决于OS界面的性能。如果您不能一次“注册”您的应用程序,然后在每次有新数据可用时继续接收通知,并在有新数据时调用read(),那么发布异步读取请求将是下一件好事。



    如果您的应用程序绝对没有其他事情要做,并且您只有一个套接字可以读取,那么这是一种好方法。换句话说,这是一种简便的方法,非常容易编程,OS本身负责完成工作,等等。请记住,尽管一旦要读取多个套接字,您将要么非常愚蠢的事情,例如每个套接字有一个线程(糟糕!),或者使用第一种方法重新编写应用程序。



    这是要走的路!实际上,这与方法#1几乎相同,只是进行了很好的优化,以尽可能少地往返内核,并一次读取了尽可能多的内容。首先,我想用这些细节来纠正第一种方法,但后来我注意到您自己做了。

    希望能帮助到你。祝好运!

    08-04 14:58