我目前正在开发一个使用面向连接的 SCTP 的服务器来为少量客户端提供服务。在完成第一个带有简单实现的原型(prototype)之后,我现在正在分析要优化的应用程序。事实证明,CPU 时间的两个主要消耗者之一是网络部分。
我实现的应用层协议(protocol)的效率有两个问题:
1) 数据包大小
目前,我使用的最大数据包大小为 64 字节。您可以找到许多讨论过大的数据包大小的帖子,但是它们可以太小吗?由于 SCTP 允许我一次读取一个数据包 - 类似于 UPD - 同时保证按顺序交付 - 类似于 TCP - 这种显着简化的实现。但是,如果我理解正确的话,每次我发送一个数据包都会花费一个系统调用。系统调用的数量是否对性能有重大影响?我能否通过以更大的数据包(即 1024 - 8192 字节)成束发送消息来减少大量 CPU 周期?
2) 读写缓冲区
我目前正在使用 memcpy 将数据移入和移出应用程序级网络缓冲区。我发现许多关于什么更有效、memcpy 或正常分配的相互矛盾的帖子。我想知道在这种情况下,一种方法是否会比另一种方法快得多:
选项 1
void Network::ReceivePacket(char* packet)
{
uint8_t param1;
uint16_t param2
uint32_t param3;
memcpy(¶m1, packet, 1);
memcpy(¶m2, packet+1, 2);
memcpy(¶m3, packet+3, 4);
// Handle the packet here
}
void Network::SendPacket(uint8_t param1, uint16_t param2, uint32_t param3)
{
char packet[7]
memcpy(&packet, ¶m1, 1);
memcpy(&packet+1, ¶m2, 2);
memcpy(&packet+3, ¶m3, 4);
// Send the packet here
}
选项 2
void Network::ReceivePacket(char* packet)
{
uint8_t param1;
uint16_t param2
uint32_t param3;
param1 = *((uint8_t*)packet);
param2 = *((uint16_t*)packet+1);
param3 = *((uint32_t*)packet+3);
// Handle the packet here
}
void Network::SendPacket(uint8_t param1, uint16_t param2, uint32_t param3)
{
char packet[7]
*((uint8_t*)packet) = param1;
*((uint16_t*)packet+1) = param2;
*((uint32_t*)packet+3) = param3;
// Send the packet here
}
第一个对我来说似乎更干净,但我发现很多帖子表明第二个可能更快一些。
当然欢迎任何类型的反馈。
最佳答案
据我所知,编译器会特别优化 memcpy 调用,因此您可能应该使用它。
关于你的第一个问题:
- 总结:使数据包大小尽可能大,避免 CPU 性能降低的可能性。
A syscall
,一个系统调用,是你的操作系统回复或处理你的请求,每次你的请求都在内核中执行,这是一个适度的工作量。
老实说,我不熟悉 SCTP
概念,事实上,自从上次处理一些东西并通过 TCP 创建服务器以来,我就没有处理过套接字编程。我记得相关物理层元素的 MTU 是 1500
,我还记得将我的数据包大小实现为 1450-1460
,因为我试图获得下面的最大数据包大小1500
上限。
所以我要说的是,如果我是你,我希望我的操作系统尽可能不活跃,这样我就不会在 CPU 性能方面遇到任何问题。
关于C++ 网络套接字、SCTP 和数据包大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18441769/