INADDR_ANY就是inet_addr("0.0.0.0")
首先,需要明確的是當服務器的監聽地址是INADDR_ANY時設置的是服務器的IP地址。
其次,當服務器的監聽地址是INADDR_ANY時含義是讓服務器端計算機上的所有網卡的IP地址都可以作為服務器IP地址,也即監聽外部客戶端程序發送到服務器端所有網卡的網絡請求。
比如,我的網絡為:192.168.1.102. 於是就有下面的程序:
服務端:
#include <stdio.h> #include <winsock2.h> // winsock接口 #pragma comment(lib, "ws2_32.lib") // winsock實現 int main() { WORD wVersionRequested; // 雙字節,winsock庫的版本 WSADATA wsaData; // winsock庫版本的相關信息 wVersionRequested = MAKEWORD(1, 1); // 0x0101 即:257 // 加載winsock庫並確定winsock版本,系統會把數據填入wsaData中 WSAStartup( wVersionRequested, &wsaData ); // AF_INET 表示采用TCP/IP協議族 // SOCK_STREAM 表示采用TCP協議 // 0是通常的默認情況 unsigned int sockSrv = socket(AF_INET, SOCK_STREAM, 0); SOCKADDR_IN addrSrv; addrSrv.sin_family = AF_INET; // TCP/IP協議族 addrSrv.sin_addr.S_un.S_addr = INADDR_ANY; //inet_addr("0.0.0.0"); addrSrv.sin_port = htons(8888); // socket對應的端口 // 將socket綁定到某個IP和端口(IP標識主機,端口標識通信進程) bind(sockSrv,(SOCKADDR*)&addrSrv, sizeof(SOCKADDR)); // 將socket設置為監聽模式,5表示等待連接隊列的最大長度 listen(sockSrv, 5); SOCKADDR_IN addrClient; int len = sizeof(SOCKADDR); while(1) { // sockSrv為監聽狀態下的socket // &addrClient是緩沖區地址,保存了客戶端的IP和端口等信息 // len是包含地址信息的長度 // 如果客戶端沒有啟動,那么程序一直停留在該函數處 unsigned int sockConn = accept(sockSrv,(SOCKADDR*)&addrClient, &len); char sendBuf[100] = {0}; sprintf(sendBuf,"%s", inet_ntoa(addrClient.sin_addr)); // 將客戶端的IP地址保存下來 send(sockConn, sendBuf, strlen(sendBuf) + 1, 0); // 發送數據到客戶端,最后一個參數一般設置為0 char recvBuf[100] = {0}; recv(sockConn, recvBuf, 100, 0); // 接收客戶端數據,最后一個參數一般設置為0 printf("%s\n", recvBuf); closesocket(sockConn); } closesocket(sockSrv); WSACleanup(); return 0; }
客戶端:
#include <winsock2.h> #include <stdio.h> #pragma comment(lib, "ws2_32.lib") int main() { WORD wVersionRequested; WSADATA wsaData; wVersionRequested = MAKEWORD(1, 1); WSAStartup( wVersionRequested, &wsaData ); SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0); SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr = inet_addr("192.168.1.102"); addrSrv.sin_family = AF_INET; addrSrv.sin_port = htons(8888); int ret = connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR)); char recvBuf[100] = {0}; recv(sockClient, recvBuf, 100, 0); printf("%s\n", recvBuf); send(sockClient, "hello world", strlen("hello world") + 1, 0); closesocket(sockClient); WSACleanup(); return 0; }
當然客戶端也可以用回測地址(設服務端與客戶端在同一台機子上):
#include <winsock2.h> #include <stdio.h> #pragma comment(lib, "ws2_32.lib") int main() { WORD wVersionRequested; WSADATA wsaData; wVersionRequested = MAKEWORD(1, 1); WSAStartup( wVersionRequested, &wsaData ); SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0); SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); addrSrv.sin_family = AF_INET; addrSrv.sin_port = htons(8888); int ret = connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR)); char recvBuf[100] = {0}; recv(sockClient, recvBuf, 100, 0); printf("%s\n", recvBuf); send(sockClient, "hello world", strlen("hello world") + 1, 0); closesocket(sockClient); WSACleanup(); return 0; }
當然啦,如果服務端用192.168.1.102作為監聽IP,客戶端用192.168.1.102去connect, 那也是可以的。
"將sin_addr設置為INADDR_ANY"的含義是什么?
問:
很多書上都說“將sin_addr設置為INADDR_ANY,則表示所有的IP地址,也即所有的計算機”,這樣的解說讓人費解。
答:
INADDR_ANY轉換過來就是0.0.0.0,泛指本機的意思,也就是表示本機的所有IP,因為有些機子不止一塊網卡,多網卡的情況下,這個就表示所有網卡ip地址的意思。
當服務器的監聽地址是INADDR_ANY時,意思不是監聽所有的客戶端IP。而是服務器端的IP地址可以隨意配置,這樣使得該服務器端程序可以運行在任意計算機上,可使任意計算機作為服務器,便於程序移植。將INADDR_ANY換成127.0.0.1也可以達到同樣的目的。這樣,當作為服務器的計算機的IP有變動或者網卡數量有增減,服務器端程序都能夠正常監聽來自客戶端的請求。我是這么理解的。
比如一台電腦有3塊網卡,分別連接三個網絡,那么這台電腦就有3個ip地址了,如果某個應用程序需要監聽某個端口,那他要監聽哪個網卡地址的端口呢?如果綁定某個具體的ip地址,你只能監聽你所設置的ip地址所在的網卡的端口,其它兩塊網卡無法監聽端口,如果我需要三個網卡都監聽,那就需要綁定3個ip,也就等於需要管理3個套接字進行數據交換,這樣豈不是很繁瑣?所以出現INADDR_ANY,你只需綁定INADDR_ANY,管理一個套接字就行,不管數據是從哪個網卡過來的,只要是綁定的端口號過來的數據,都可以接收到。