我试图确保每次调用socket.send函数时,我的缓冲区被发送(刷新)到我的服务器(使用unix套接字在C中)。
根据我的理解(以及我在这个板上看到的内容),只是禁用了naggle算法。应该这样做,但我的服务器仍然以4096字节(默认设置)...
的块接收我的数据我在Python v2.5.4中使用以下代码:
self.sck = socket( AF_INET, SOCK_STREAM )
self.sck.setsockopt( IPPROTO_TCP, TCP_NODELAY, 1 ) # That doesn't seems to work...
self.sck.connect( ( "127.0.0.1", "12345" ) )
while( 1 ):
self.sck.send( "test\n" )
self.sck.send( "" ) # Still trying to flush...
启用/禁用TCP_NODELAY似乎没有任何影响......这是一个错误还是我遗漏了什么?
TIA
答案 0 :(得分:7)
TCP不提供任何类型的保证“数据包”发送到另一端。您正在尽可能快地发送数据,并且TCP有助于将数据批处理到尽可能多的时间。您的服务器一次接收4096字节的数据,这可能是因为它要求的内容(在recv()
调用中)。
TCP是一种流协议,因此您必须自己实现某种框架。没有内置的消息边界。
答案 1 :(得分:5)
我获得同花顺(回到C客户端)的唯一方法是使用:
my_writer_obj = mysock.makefile(mode='w', ...)
my_writer_obj.write('my stuff')
my_writer_obj.flush()
最大的好处是my_writer_obj默认为文本模式,因此不再需要字节翻译。
创建一个阅读器对象并不顺利,但我不需要那边的同花顺。
答案 2 :(得分:4)
无法确保发送的数据块的大小。如果要确保发送所有要发送的数据,可以关闭连接:
self.sck.close()
另请注意,n = socket.send()返回实际发送的字节数。如果您确定要发送所有数据,则应使用
self.sck.sendall()
或循环数据发送:
while data:
n = self.sck.send(data)
data = data[n:]
(但这与sendall()大致相同)。 如果要以更大的块接收数据,可以在recv()中增加缓冲区的大小,但这只会使可能的块大小更大。没有保证数据以这些尺寸到达。
答案 3 :(得分:1)
这是关于TCP协议的常见问题。 TCP本身无法以特定块发送数据。它仅用于发送数据流。如果您需要此类功能,则应自行实施。例如,在单独的行中发送您的块,或者首先发送块大小,然后发送块本身。
在大多数情况下,您不需要关心Naggle算法。该算法更好地用名称TCP_NODELAY描述。如果你禁用它,你可以实现小块的较小延迟,但同时降低大块的速度。
答案 4 :(得分:0)
在 Linux 中,这可以通过调用 ioctl
来实现:
SIOCOUTQ
返回套接字发送队列中未发送的数据量。 > 套接字不得处于 LISTEN 状态,否则将返回错误 (EINVAL)。
SIOCOUTQ 在
快速查看linux/sockios.h
:
/* Linux-specific socket ioctls */
#define SIOCINQ FIONREAD
#define SIOCOUTQ TIOCOUTQ /* output queue size (not sent + not acked) */
因此,应用此方法相当容易:
import socket
def flush_socket(sock: socket.socket) -> bool:
from ctypes import c_ulong
from time import sleep
from termios import TIOCOUTQ
from fcntl import ioctl
while sock.fileno() != -1: # if fd is -1, then it has been probably close()'d
remaining = c_ulong.from_buffer_copy(
ioctl(sock.fileno(), TIOCOUTQ, bytearray(8), False)).value
if remaining == 0:
# all data has been sent and ACKed
return True
# wait a bit before retrying,
# sleep(0) was meant like yield current thread,
# but will probably be close to busy-waiting,
# feel free to change it to fit your needs
sleep(0)
# not all data has been sent
return False