網絡編程實驗1_(9)獲取本機的IP地址(C++代碼)


#define  _WINSOCK_DEPRECATED_NO_WARNINGS #include<iostream> #include<WinSock2.h> #include<string>
#pragma comment(lib,"ws2_32.lib")

using namespace std; int main() { WSADATA wsaData; // WSADATA結構包含有關Windows套接字實現的信息。
    WORD wVersionRequest;     // wVersionRequested 為 WinSock 規范的版本號,低字節為主版本號,高字節為副版本號(修正版本號)
    int iResult;             // WSAStartup()的返回值,如果為零,則成功啟動網絡庫
    char name[256];          // 指向接收本地主機名的緩沖區的指針。
    PHOSTENT hostinfo;         // PHOSTENT類型,本質上是一個指向hostent的結構體指針
 wVersionRequest = MAKEWORD(2, 2); iResult = WSAStartup(wVersionRequest, &wsaData); if (0 != iResult) { switch (iResult) { case WSASYSNOTREADY: cout << "底層網絡子系統還沒有准備好進行網絡通信。" << endl; break; case WSAVERNOTSUPPORTED: cout << "此特定的Windows Sockets實現不提供所請求的Windows Sockets支持的版本。" << endl; break; case WSAEINPROGRESS: cout << "正在執行阻塞Windows Sockets 1.1操作。" << endl; break; case WSAEPROCLIM: cout << "已達到Windows Sockets實現支持的任務數量的限制。" << endl; break; case WSAEFAULT: cout << "lpWSAData參數不是有效指針。" << endl; break; } } /* 確認WinSock DLL支持2.2。注意,如果DLL支持的版本除2.2外大於2.2,它仍將在wversion中返回2.2,因為這是我們請求的版本 */

    if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion != 2)) { cout << "找不到Winsock.dll的可用版本" << endl; WSACleanup(); return 1; } else cout << "發現了Winsock 2.2 DLL" << endl; /* gethostname中有兩個參數,第一個name是指向接收主機名的緩沖區的指針,第二個參數是緩沖區的長度(以字節為單位) gethostbyname中的參數是域名字符串或者指向主機名的指針 LPCSTR是Win32和VC++所使用的一種字符串數據類型。LPCSTR被定義成是一個指向以'\0'結尾的常量字符的指針。 inet_ntoa函數將(IPv4)Internet網絡地址轉換為Internet標准虛數點分十進制格式的ASCII字符串。 in_addr結構表示IPv4 Internet地址。 hostinfo在開頭定義了,它是PHOSTENT類型,本質上是一個指向hostent的結構體指針,所以雖然沒把hostent在代碼中寫出來,但必須弄清楚 h_addr_list,這個是地址列表,是hostent結構體中最重要的成員變量,通過該成員以整數形式保存域名對應的 IP 地址 */
    string ServAddr; if (gethostname(name, sizeof(name)) == 0) { if ((hostinfo = gethostbyname(name)) != NULL) { //LPCSTR ip = inet_ntoa(*(struct in_addr*) * hostinfo->h_addr_list);
            ServAddr = inet_ntoa(*(struct in_addr*) * hostinfo->h_addr_list); //ServAddr = ip;
            cout << "本機(此處作為服務器)的IP 為:" << ServAddr << endl; //cout << "本機(此處作為服務器)的IP 為:" << ip << endl;
       //如果將被注釋掉的這三行來代替這兩行代碼的話也是可以的
} } else { switch (gethostname(name, sizeof(name))) { case WSAEFAULT: cout << "name參數是空指針,或者不是用戶地址空間的有效部分。如果namelen參數指定的緩沖區大小太小,無法容納完整的主機名,也會返回此錯誤。" << endl; break; case WSANOTINITIALISED: cout << "在使用此函數之前,必須進行成功的WSAstartup調用。" << endl; break; case WSAENETDOWN: cout << "網絡子系統失敗。" << endl; break; case WSAEINPROGRESS: cout << "阻塞Windows套接字1.1調用正在進行,或者服務提供者仍在處理回調函數。" << endl; break; } } WSACleanup(); // 在socket編程中,必須以WSACleanup()結尾 system("pause"); return 0; }

和上一篇網絡編程實驗1_(8)獲得給定域名的IP地址(C++代碼)一樣,我通常喜歡把詳細的解釋放在注釋中。

但是獲得本機的IP地址和獲得給定域名的IP地址有何區別呢?

相同之處在於我們使用的獲得IP地址的方法都是通過gethostbyname()這個函數實現的。

這個函數的返回值為一個結構體指針,指向的結構體是hostent,可以通過轉到定義查看,

 

 

 

我在程序中使用的就是這個結構體中的成員變量h_addr_list,這其實是一個指針數組,

用來存放解析出來的多個IP地址。

 

和獲得給定域名IP地址不同的是,獲得本機的IP地址用到了gethostname()這個函數。

這個函數有兩個參數,第一個參數是指向接收主機名的緩沖區的指針,別被修飾詞繞暈了,它是指向緩沖區的指針。

第二個參數是這個緩沖區的大小。

至於這個緩沖區的大小該設置為多少,MSDN上給出的解釋是這樣的(我翻譯過后的):

 

 

 所以我也就索性設置為了256字節。

這個函數如果運行成功了,返回一個零,否則返回一個錯誤碼。

至於錯誤碼的含義,你可以不用搞清楚,至少對於有耐心看我這個菜鳥寫的博客的你來說,應該是沒有任何意義的。

所以如果你想簡單一點,可以把這個啰嗦的switch case去掉,從else開始,直接刪掉也是沒有任何問題的。

 

這個任務最重要的是理解hostent這個結構體,以及如何將這個結構體的成員變量中得到IP地址,並轉換為我們需要的形式。

如果你覺得我講的不夠清楚的,可以看看我之前的博客,或者去網上查一查hostent、以及inet_ntoa()等等。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM