C中socket recv的char连接操作效率最大化
Maximizing efficiency of char concatenation operation for socket recv in C
我试图最大限度地提高从套接字接收到的充满数据的缓冲区并将其复制到全局字符数组时的效率 xmlResponce[35000]
。
char buf[2048];
if (sendResponce != -1)
{
int bytes;
memset(buf, '[=10=]', 2048);
while((bytes = recv(sockfd, buf, 2047, 0)) > 0)
{
buf[bytes] = '[=10=]';
strcat(xmlResponce, buf);
}
}
我特别关心最小化内存碎片,因为我在 Linux 内核 2.6.27 上有一些问题。有没有更有效的方法来做到这一点?使用 strcat
是否是从缓冲区复制到主字符数组的正确选择?
除非您在代码中的某处执行 malloc/realloc/free(似乎并非如此),否则应该没有碎片问题。
主要问题是您的代码在重新扫描每个 strcat 上的 xmlResponse 时,接收数据的长度是二次方的。 Strcat 不是最佳选择,因为您已经知道长度
if (sendResponce != -1)
{
int bytes, offset = 0;
while((bytes = recv(sockfd, buf, 2047, 0)) > 0 &&
offset+bytes < sizeof(xmlResponce)-1)
{
memcpy(xmlResponce+offset, buf, bytes);
offset+= bytes;
}
xmlResponse[offcet]=0;
}
首先,我认为您可能想多了。内核内存碎片(如您对内核的引用所示)是物理 RAM 的碎片,这意味着伙伴算法无法分配物理上连续的页面。但是,由于您的内存是虚拟内存,这并不重要,因为虚拟连续内存不需要在物理上连续。虚拟内存碎片取决于您如何在用户 space(libc 或其他)中分配页面。
如果你真的担心虚拟内存碎片,那么使用mmap( ... MAP_ANON ... )
分配一个大数组。让它比您可能需要的大(它实际上不会消耗物理内存,直到您写入或读取每个页面),然后 mremap
如果您需要扩展它,它的大小会增加一倍。如果您查看 man mallopt
(特别是 M_MMAP_THRESHOLD
),您会发现如果您使原始分配足够大,malloc()
将为您完成所有工作。所以我建议你只分配一个大缓冲区(如果你愿意的话,35000 字节),然后如果你要溢出它,加倍大小。
现在,如何将字节写入缓冲区?
不要使用 strcat
。只需将它们直接写入缓冲区即可。根本不需要复制东西。这是一些未经测试的代码。
ssize_t offset = 0;
....
if (sendResponce != -1)
{
ssize_t bytes;
while((bytes = recv(sockfd, xmlResponse+offset, 65536, 0)) > 0)
{
offset += bytes;
}
}
xmlResponse[offset] = 0;
请注意,为了提高效率,我已将 recv
的大小增加到 65536 字节。这意味着通常您会在一个电话中得到它。
不要忘记检查您的写入是否超出了缓冲区的末尾。为了清楚起见,我省略了它。
我试图最大限度地提高从套接字接收到的充满数据的缓冲区并将其复制到全局字符数组时的效率 xmlResponce[35000]
。
char buf[2048];
if (sendResponce != -1)
{
int bytes;
memset(buf, '[=10=]', 2048);
while((bytes = recv(sockfd, buf, 2047, 0)) > 0)
{
buf[bytes] = '[=10=]';
strcat(xmlResponce, buf);
}
}
我特别关心最小化内存碎片,因为我在 Linux 内核 2.6.27 上有一些问题。有没有更有效的方法来做到这一点?使用 strcat
是否是从缓冲区复制到主字符数组的正确选择?
除非您在代码中的某处执行 malloc/realloc/free(似乎并非如此),否则应该没有碎片问题。
主要问题是您的代码在重新扫描每个 strcat 上的 xmlResponse 时,接收数据的长度是二次方的。 Strcat 不是最佳选择,因为您已经知道长度
if (sendResponce != -1)
{
int bytes, offset = 0;
while((bytes = recv(sockfd, buf, 2047, 0)) > 0 &&
offset+bytes < sizeof(xmlResponce)-1)
{
memcpy(xmlResponce+offset, buf, bytes);
offset+= bytes;
}
xmlResponse[offcet]=0;
}
首先,我认为您可能想多了。内核内存碎片(如您对内核的引用所示)是物理 RAM 的碎片,这意味着伙伴算法无法分配物理上连续的页面。但是,由于您的内存是虚拟内存,这并不重要,因为虚拟连续内存不需要在物理上连续。虚拟内存碎片取决于您如何在用户 space(libc 或其他)中分配页面。
如果你真的担心虚拟内存碎片,那么使用mmap( ... MAP_ANON ... )
分配一个大数组。让它比您可能需要的大(它实际上不会消耗物理内存,直到您写入或读取每个页面),然后 mremap
如果您需要扩展它,它的大小会增加一倍。如果您查看 man mallopt
(特别是 M_MMAP_THRESHOLD
),您会发现如果您使原始分配足够大,malloc()
将为您完成所有工作。所以我建议你只分配一个大缓冲区(如果你愿意的话,35000 字节),然后如果你要溢出它,加倍大小。
现在,如何将字节写入缓冲区?
不要使用 strcat
。只需将它们直接写入缓冲区即可。根本不需要复制东西。这是一些未经测试的代码。
ssize_t offset = 0;
....
if (sendResponce != -1)
{
ssize_t bytes;
while((bytes = recv(sockfd, xmlResponse+offset, 65536, 0)) > 0)
{
offset += bytes;
}
}
xmlResponse[offset] = 0;
请注意,为了提高效率,我已将 recv
的大小增加到 65536 字节。这意味着通常您会在一个电话中得到它。
不要忘记检查您的写入是否超出了缓冲区的末尾。为了清楚起见,我省略了它。