c++ - Boost Asio 访问 asio::ip::address 底层数据和字节顺序
问题描述
我的目标是为所有 IP 地址 - 端口对创建一个唯一 ID。跨系统的 UID 必须相同(不同字节序系统没有冲突)。IPV4 UID 的大小为 6 个字节,而 ipv6 为 18 个字节。
uint8_t sourcePair[18]; /*ipv4=(4+2) bytes or ipv6=(16+2) bytes*/
我有两个函数将获取套接字的远程端点并获取所需的 UID。设计如下。
void CmdInterpreter::makeSourcePairV4(asio::ip::tcp::endpoint& remoteEp, unsigned short portNum, unsigned char(&binSourcePair)[18])
{
auto addressClass = remoteEp.address().to_v4();
auto ipBin = addressClass.to_uint();
memcpy(&binSourcePair[0], &ipBin, 4);
memcpy(&binSourcePair[4], &portNum, 2);
}
void CmdInterpreter::makeSourcePairV6(asio::ip::tcp::endpoint& remoteEp, unsigned short portNum, unsigned char(&binSourcePair)[18])
{
auto addressClass = remoteEp.address().to_v6();
auto ipBin = addressClass.to_bytes();
memcpy(&binSourcePair[0], &ipBin[0], 16);
memcpy(&binSourcePair[16], &portNum, 2);
}
这就是这些函数的调用方式
remoteEp = socketPtr->remote_endpoint();
if (remoteEp.address().is_v4())
CmdInterpreter::makeSourcePairV4(remoteEp, remoteEp.port(), sourcePair);
else
CmdInterpreter::makeSourcePairV6(remoteEp, remoteEp.port(), sourcePair);
这里的问题是访问 IPv6 底层数据的唯一方法是使用 to_byte() ,它将以网络字节顺序提供数据。另外,我正在做一个无符号短的内存复制,它的长度是多字节的。这行得通吗?这是一种安全的方式吗?他们有什么解决方法吗?
解决方案
void CmdInterpreter::makeSourcePairV4(asio::ip::tcp::endpoint& remoteEp, unsigned short portNum, uint8_t(&sourcePair)[18])
{
auto addressClass = remoteEp.address().to_v4();
auto ipBin = addressClass.to_bytes();
memcpy(&sourcePair[0], &ipBin[0], 4);
#ifdef BOOST_ENDIAN_LITTLE_BYTE
byteSwap(portNum);
#endif
memcpy(&sourcePair[4], &portNum, 2);
}
void CmdInterpreter::makeSourcePairV6(asio::ip::tcp::endpoint& remoteEp, unsigned short portNum, uint8_t(&sourcePair)[18])
{
auto addressClass = remoteEp.address().to_v6();
auto ipBin = addressClass.to_bytes();
memcpy(&sourcePair[0], &ipBin[0], 16);
#ifdef BOOST_ENDIAN_LITTLE_BYTE
byteSwap(portNum);
#endif
memcpy(&sourcePair[16], &portNum, 2);
}
对于 IPv4 和 IPv6 地址,使用 to_byte() 函数以大端格式获取远程端点地址。对于 little-endian 主机,端口号会产生字节顺序问题,可以通过交换字节来解决。要将其编码为 base 64,我使用了 cppcodec 库。
UID = cppcodec::base64_rfc4648::encode(sourcePair, 6);
UID = cppcodec::base64_rfc4648::encode(sourcePair, 18);
用于交换端口号的模板函数是:
template <typename T>
void byteSwap(T& portNumber)
{
char* startIndex = static_cast<char*>((void*)&portNumber);
char* endIndex = startIndex + sizeof(T);
std::reverse(startIndex, endIndex);
}
推荐阅读
- php - Symfony 路由:_controller 特殊参数
- angular - 使用 FormArray 的 Angular Material 可编辑表
- c++ - CMake 生成的程序无法在 Windows 上链接:尝试链接到不存在的文件
- tensorflow - Gcloud FileNotFound - 机器学习引擎
- java - Corda 自定义文件上传端点
- c# - 在Firefox中使用Windows身份验证时访问网络共享文件
- vba - 如何将树视图类导出到 VBA Excel 中的不同工作簿?
- pytest - 如果第一个测试失败,如何使用不同的参数重新运行测试用例
- javascript - 在 Javascript 中扩展的模板
- numpy - Numpy 无法使用某些名称保存