编写WinSock代码时,相信大家一般都会使用inet_addr
函数来将点分十进制字符串转换为sin_addr.S_un.S_addr
,如下
SOCKADDR_IN sockaddr;
sockaddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
但是,由于inet_addr
函数没有错误判断机制,所以导致传入错误的点分十进制字符串时,inet_addr
函数还是会执行成功,然后会出现让人哭笑不得的现象,如下
SOCKADDR_IN sockaddr;
sockaddr.sin_addr.S_un.S_addr = inet_addr("127");
auto pAddr = inet_ntoa(sockaddr.sin_addr);
if (pAddr != NULL)
{
std::cout << pAddr << "\n";
}
sockaddr.sin_addr.S_un.S_addr = inet_addr("127.1");
pAddr = inet_ntoa(sockaddr.sin_addr);
if (pAddr != NULL)
{
std::cout << pAddr << "\n";
}
上述代码在VS2017上运行结果如下
输出的结果完全跟传入的参数不符。
所以说,编写WinSock代码时,不推荐使用inet_addr
函数,应该使用inet_pton
函数转换点分十进制字符串,代码如下
SOCKADDR_IN sockaddr;
char szAddress[255] = { 0, };
int nRetValue = inet_pton(AF_INET, "127", &sockaddr.sin_addr);
if (nRetValue != 0)
{
auto pAddress = inet_ntop(AF_INET, &sockaddr.sin_addr, szAddress, sizeof(szAddress));
if (pAddress != NULL)
{
std::cout << pAddress << '\n';
}
}
nRetValue = inet_pton(AF_INET, "127.1", &sockaddr.sin_addr);
if (nRetValue != 0)
{
auto pAddress = inet_ntop(AF_INET, &sockaddr.sin_addr, szAddress, sizeof(szAddress));
if (pAddress != NULL)
{
std::cout << pAddress << '\n';
}
}
nRetValue = inet_pton(AF_INET, "127.0.0.1", &sockaddr.sin_addr);
if (nRetValue != 0)
{
auto pAddress = inet_ntop(AF_INET, &sockaddr.sin_addr, szAddress, sizeof(szAddress));
if (pAddress != NULL)
{
std::cout << pAddress << '\n';
}
}
上述代码在VS2017上的运行结果如下
可见,当输入的点分十进制格式错误时,inet_pton
函数返回零值,否则返回非零值。更多关于inet_pton
函数的介绍可浏览这个网站:https://docs.microsoft.com/en-us/windows/win32/api/ws2tcpip/nf-ws2tcpip-inet_pton。
至于关于inet_addr
函数的介绍网站为:https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-inet_addr,inet_ntoa
函数的介绍网站为:https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-inet_ntoa,inet_ntop
函数的介绍网站为:https://docs.microsoft.com/en-us/windows/win32/api/ws2tcpip/nf-ws2tcpip-inet_ntop。
在我看来,inet_ntoa
函数和inet_ntop
函数在一般的使用情况下是没有区别,但是inet_ntoa
函数不支持ipv6。转换失败时inet_ntoa
函数和inet_ntop
函数都是返回NULL。
但是呢,inet_pton
函数和inet_ntop
函数是Windows Vista及以后的版本才支持的,那运行在Windows XP上程序咋办呢?(PS:别跟我说Windows XP早就没人用了,T_T在你想不到的地方还有很多使用着Windows XP的古董机。)
由于Windows没有提供inet_aton
函数,所以呢我们不可避免地要去使用inet_addr
函数。那么我们就可以在执行inet_addr
函数转换前使用正则表达式来判断一下字符串是否是正确的ipv4地址,代码如下
std::regex regexIpAddress("(?=(\\b|\\D))(((\\d{1,2})|(1\\d{1,2})|(2[0-4]\\d)|(25[0-5]))\\.){3}((\\d{1,2})|(1\\d{1,2})|(2[0-4]\\d)|(25[0-5]))(?=(\\b|\\D))");
if (!std::regex_match("127", regexIpAddress))
{
std::cout << "not match\n";
}
else
{
std::cout << "match\n";
}
if (!std::regex_match("127.1", regexIpAddress))
{
std::cout << "not match\n";
}
else
{
std::cout << "match\n";
}
if (!std::regex_match("127.0.0.1", regexIpAddress))
{
std::cout << "match\n";
}
else
{
std::cout << "match\n";
}
上述代码在VS2017上的执行结果如下
关于C++的正则表达式库可以查看这个网址:https://zh.cppreference.com/w/cpp/regex。
以上就是本博客的全文,本人限于能力,上文中难免有错误的地方,若读者发现上文的错误,请于评论区中指出,本人看到之后会立即修改的,谢谢。