編寫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。
以上就是本博客的全文,本人限於能力,上文中難免有錯誤的地方,若讀者發現上文的錯誤,請於評論區中指出,本人看到之後會立即修改的,謝謝。