我正在研究用于linux系统的非阻塞C tcp套接字。我已经读到,在非阻塞模式下,"发送"命令将返回"发送的字节"如果没有错误立即。我猜测这个返回的值实际上并不意味着这些数据已经传递到目的地,而是数据已经传递到内核内存,以便进一步处理和发送。
如果是这种情况,我的应用程序将如何知道哪个数据包确实已经由内核发送到另一端,假设网络连接存在一些问题并且内核决定仅在几次重试之后才放弃几分钟后?
我问,因为我希望我的应用程序稍后再次重新发送这些失败的数据包。
答案 0 :(得分:3)
如果是这种情况,我的应用程序将如何知道哪个数据包有 真的是由内核发送到另一端,假设是 网络连接有一些问题,内核决定放弃 只是在几分钟之后的几次重试之后?
您的应用程序不知道,除非它能够重新接收接收应用程序并询问接收应用程序以前收到的数据。
请记住,即使使用阻止I / O,您的应用程序也不会阻塞,直到远程应用程序收到数据 - 它只会阻塞,直到内核中有一些空间输出数据缓冲区,用于保存您要求TCP堆栈发送的字节数()。因此,即使阻止I / O,您也会遇到同样的问题。
还要记住,传递给send()的字节数组与TCP堆栈发出的TCP数据包没有保证一对一的对应关系。 TCP堆栈可以随心所欲地将您的字节打包成TCP数据包(例如,来自多个send()调用的数据可以在一个TCP数据包中结束,或者来自单个send()调用的数据可以以多个数据包结束TCP数据包,或您可以想到的任何其他组合)。根据网络状况,TCP堆栈可以并且以不同的方式打包,它们唯一的承诺是以FIFO顺序接收字节(如果它们完全被接收)。
无论如何,你的问题的答案是:你不能知道,除非你后来问接收程序它得到了什么(或者没有得到)。
答案 1 :(得分:-1)
TCP内部负责重试,应用程序不需要对其进行任何特殊处理。如果您希望确认收到TCP堆栈另一端的数据包,则可以将发送套接字缓冲区(setsockopt(SOL_SOCKET, SO_SNDBUF)
)设置为零。在这种情况下,内核使用您的应用程序缓冲区来发送数据和它仅在TCP收到此数据的确认后才发布。这样您就可以确认数据被推送到TCP堆栈的接收端。它不确认应用程序是否已收到数据。您需要在协议中具有应用层确认,以确认数据已到达接收器应用程序。