有没有办法刷新POSIX套接字?

时间:2009-05-13 00:42:58

标签: c sockets posix

是否有标准调用将POSIX套接字的发送端一直刷新到远程端,或者这是否需要作为用户级协议的一部分实现?我环顾了常见的标题,却找不到任何东西。

9 个答案:

答案 0 :(得分:25)

如何设置TCP_NODELAY并重新设置? 可能在发送重要数据之前,或者在完成发送消息之后就可以完成。

send(sock, "notimportant", ...);
send(sock, "notimportant", ...);
send(sock, "notimportant", ...);
int flag = 1; 
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
send(sock, "important data or end of the current message", ...);
flag = 0; 
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));

正如linux手册页所说

  

TCP_NODELAY ...设置此选项会强制显式刷新待处理的输出...

所以可能最好在消息之后设置它,但不确定它在其他系统上是如何工作的

答案 1 :(得分:16)

对于Unix域套接字,您可以使用fflush(),但我认为您可能意味着网络套接字。没有真正的冲洗概念。最接近的是:

  1. 在会话结束时,调用shutdown(sock, SHUT_WR)关闭套接字上的写入。

  2. 在TCP套接字上,使用sockopt TCP_NODELAY禁用Nagle算法,这通常是一个可怕的想法,即使它似乎在初步调查中处理它,也不能可靠地做你想要的。

  3. 处理任何问题都很可能是在用户协议级别上调用'flush'将是正确的。

答案 2 :(得分:7)

我无法在标准的TCP / IP套接字接口中知道将数据“一直刷到远端”并确保它已被实际确认。

一般来说,如果您的协议需要“实时”传输数据,通常最好的办法是设置setsockopt() TCP_NODELAY。这会禁用协议栈中的Nagle算法,并且套接字上的write()或send()更直接映射到网络上发送....而不是实现发送保持等待更多字节变为可用并使用所有TCP级别计时器决定何时发送。注意:关闭Nagle不会禁用TCP滑动窗口或任何东西,因此它总是安全的....但如果您不需要“实时”属性,数据包开销可能会上升很多。

除此之外,如果正常的TCP套接字机制不适合您的应用程序,那么通常您需要回退使用UDP并在UDP的基本发送/接收属性上构建自己的协议功能。当您的协议有特殊需求时,这是非常常见的,但是不要低估这样做的复杂性,并且除了相对简单的应用程序之外,在所有这些方面都要保持稳定和功能正确。作为一个起点,对TCP设计特征的深入研究将揭示需要考虑的许多问题。

答案 3 :(得分:7)

在RFC 1122中,您要查找的内容的名称是“PUSH”。 虽然我不知道任何实现“PUSH”的TCP API。

一些答案​​和评论涉及Nagle算法。他们中的大多数似乎都认为Nagle算法会延迟每次发送。这种假设是不正确的。仅当先前的数据包尚未被确认时,Nagle才会延迟发送(http://www.unixguide.net/network/socketfaq/2.11.shtml)。

为了简化一点:TCP尝试立即发送第一个数据包(一行数据包),但延迟后续数据包直到超时为止到达或第一个数据包被确认 - 以先发生者为准。

一种解决方案是避免这些“后续数据包”。如果您的应用程序调用send()多次传输单个复合请求,请尝试重写您的应用程序。在用户空间中汇编请求,然后调用send()。一次。

此外,当发送缓冲区包含足够的数据来填充网络数据包的最大大小时,Nagle也不会延迟。这意味着,即使您将批量数据send()分成小块,Nagle也不会(实际)延迟批量发送。

答案 4 :(得分:1)

我认为如果不是不可能正确实施那将是非常困难的。在这种情况下,“冲洗”是什么意思?字节传输到网络?接收方的TCP堆栈确认的字节数?字节传递给接收者的用户模式应用程序?字节是否完全由用户模式应用程序处理?

看起来您需要在应用级别执行此操作...

答案 5 :(得分:0)

TCP只提供尽力而为的交付,因此让所有字节离开机器A的行为是异步的,它们都是在机器B上接收的。当然,TCP / IP协议栈知道,但我不知道知道任何询问TCP堆栈的方法,以确定发送的所有内容是否已被确认。

到目前为止,处理问题的最简单方法是在应用程序级别。打开第二个TCP套接字作为反向通道,让远程伙伴向您发送确认信息,表明它已收到您想要的信息。它的成本是双倍的,但是可以完全移植,并且可以节省数小时的编程时间。

答案 6 :(得分:0)

您可以设置tcp选项SO_LINGER以设置特定超时,然后关闭套接字以确保在关闭连接时已发送所有数据(或检测到无法执行此操作)。除此之外,TCP是一种“尽力而为”的协议,并没有提供数据实际到达目的地的任何真正保证(与一些人似乎相信的相反),它只是尽力将其交付正确的顺序,并尽快。

答案 7 :(得分:0)

有一个 linux-specific way 可以在 TCP 套接字上执行此操作:

您不会强制 tcp 堆栈“立即发送数据”,但请记住您和内核正在尽可能快地发送数据。您可以使用 <!DOCTYPE html> <html> <head> <%= title %> </head> <body> <% image.forEach((image)=> { %> <div> <img src="data:image/<%=image.img.contentType%>;base64, <%=image.img.data.toString('base64')%>"> </div> <% }) %> </body> </html> 稍微减少 send 和实际交付之间的延迟。

但基本上,通过执行 TCP_NODELAY 你已经完成了你的部分,你只需要等待 tcp 完成它的部分。

您可以在套接字上使用 sendioctlSIOCOUTQ 来查询交付状态并等待它完成。这应该足够了。特别是对于发送应用级数据包片段等用例。

答案 8 :(得分:-2)

使用fsync():

sock_fd是来自socket(...,...)call

的整数文件描述符

FSYNC(sock_fd);