所以我在TCP套接字上发送数据,前缀为数据大小,如下所示:
write(socket, &length, sizeof(length));
write(socket, data, length);
(注意:我有Unix网络编程书中描述的包装器写入功能,我正在检查错误等。以上只是为了简化这个问题。)
现在,我的经验是将数据分解为多次写入会导致显着减速。通过创建自己的缓冲区,然后发送一个大块,我已经成功地加快了速度。
然而,在上述情况下,数据可能非常大(比如1 Gig)。我不想创建1千兆字大+4字节的缓冲区,只是为了能够进行一次write()调用。有没有办法做类似的事情:
write(socket, &length, data, sizeof(length) + length)
没有提前支付大量内存分配的价格?我想我可以预先分配一个与写缓冲区大小相同的块,并不断发送(下面的代码有错误,即在某些情况下应该发送& chunk + 4,但这只是想法):
length += 4;
char chunk[buffer_size];
var total = 0;
while (total < length)
{
if (total < 4)
{
memcpy(&chunk, &length, 4);
total += 4;
}
memcpy(&chunk, data + total, min(buffer_size, length - total));
write(sock, &chunk, min(buffer_size, length - total));
total += min(buffer_size, length - total);
}
但在这种情况下,我不知道写的缓冲区大小究竟是什么(有没有API可以获得它?)我也不知道这是否是一个合适的解决方案。< / p>
答案 0 :(得分:4)
有一个选项可以做到这一点。它将告知您的网络层您将要发送更多数据,并且您想要缓冲而不是尽快发送它。
setsockopt(sock_descriptor, IPPROTO_TCP, TCP_CORK, (char *)&val, sizeof(val));
val是一个int,应该是0或1,&#34; cork&#34;在,你的网络层将尽可能缓冲的东西,只发送完整的数据包,你可能想要&#34;弹出软木塞&#34;和&#34;软木塞&#34;再次处理你需要在插座上进行的下一批传输。
您的想法是正确的,这样可以省去实施它的麻烦,因为它已经在网络堆栈中完成了。
答案 1 :(得分:3)
我建议您查看writev()
(有关完整详情,请参阅man writev
。)
这允许您一次发送多个缓冲区,只需一次调用。举个简单的例子,一次发送两个块(一个用于长度,一个用于数据):
struct iovec bits[2];
/* First chunk is the length */
bits[0].iov_base = &length;
bits[0].iov_len = sizeof(length);
/* Second chunk is the payload */
bits[1].iov_base = data;
bits[1].iov_base = length;
/* Send two chunks at once */
writev(socket, bits, 2);
如果需要使用可变数量的块(可能需要动态分配struct iov
数组),它会变得更复杂,但优点是,如果你的块很大,你可以避免复制它们,只需操作指针/长度对,它们要小得多。
答案 2 :(得分:2)
我认为你的假脱机解决方案已经出现在正确的轨道上。我认为buffer_size应该大于网络堆栈内部使用的缓冲区。这样,您可以最大限度地减少每次写入开销的数量,而无需分配巨大的缓冲区。换句话说,通过为底层网络子系统提供比它能够同时处理的数据更多的数据,它可以以最快的速度运行,花费大部分时间来移动数据,而不是等待提供更多的数据。
最佳buffer_size值可能因系统而异。我将从1MB开始,从那里上下做一些实验,看看哪种方法效果最好。您可以使用sysctl调用提取和调整值,以获取系统上使用的当前内部缓冲区大小。阅读this以获取建议的技巧。您也可以使用getsockopt(..., SO_MAX_MSG_SIZE, ...)
之类的内容,如here所述。
以太网数据包的大小最大可达64K,因此任何大于64K的数据都可能就足够了。阅读有关maximum transmission unit(MTU)大小的信息,以了解网络堆栈的最低层正在做什么,并且不要忘记MTU随网络接口而变化,而不是进程或内核。
请注意,MTU可能会随着从服务器到数据目的地的路径而变化。您可以使用ifconfig或traceroute/tracepath来发现它。通过网络,链中的每个环节都很薄弱。 ;)