Server端bind本机IP地址使用INADDR_ANY

如果bind绑定的是INADDR_ANY,即表示所有发送到服务器的这个端口,不管是哪个网卡/哪个IP地址接收到的数据,都由这个服务端进程进行处理。

一般情况下,如果你要建立网络服务器应用程序,则你要通知服务器操作系统:请在某地址 xxx.xxx.xxx.xxx上的某端口 yyyy上进行侦听,并且把侦听到的数据包发送给我。这个过程,你是通过bind()系统调用完成的。——也就是说,你的程序要绑定服务器的某地址,或者说:把服务器的某地址上的某端口占为已用。服务器操作系统可以给你这个指定的地址,也可以不给你。

如果你的服务器有多个网卡(每个网卡上有不同的IP地址),而你的服务(不管是在udp端口上侦听,还是在tcp端口上侦听),出于某种原因:可能是你的服务器操作系统可能随时增减IP地址,也有可能是为了省去确定服务器上有什么网络端口(网卡)的麻烦 —— 可以要在调用bind()的时候,告诉操作系统:“我需要在 yyyy 端口上侦听,所有发送到服务器的这个端口,不管是哪个网卡/哪个IP地址接收到的数据,都是我处理的。”这时候,服务器程序则在0.0.0.0这个地址上进行侦听。例如:

Proto Recv-Q Send-Q Local Address Foreign Address (state)

……

udp4 0 0 *.7913 *.*

udp4 0 0 *.7911 *.*

tcp4 0 0 *.ftp *.* LISTEN

……

……

以上这些是网络侦听的情况,其中Local Address 为 “*.ftp”、“*.7911”等,代表了服务程序绑定了服务器的所有网卡。

好了,你明白了侦听INADDR_ANY是什么意思了,那么,我的服务器有N个IP地址,会不会收到重复的数据包?收到数据包后,是不是会重复回复客户端呢?

答案是:不会收到重复的数据包,也不会重复发送数据。

为什么呢?因为路由的关系,从客户端来的IP包只可能到达其中一个网卡。同时在服务器进程发送数据时,操作系统根据自身维护着的路由表,决定IP数据包应该从哪一个outbound的gateway向目标端发送。根据gateway选择的不同,也就决定了从哪一个网卡/哪个IP地址发送。

为什么不会接收到重复的数据包呢?

答:因为客户端只向你的服务器上的唯一一个IP地址发送数据了。

为什么不会重复发送数据包呢?

答:因为发送数据包的路由(路径)是唯一的。如果服务器不知道在发送数据的时候应该向哪个地址发送数据,那么数据就会被发送到“默认网关”上。

如何选择发送数据的路径呢?

答:依照路由表的要求发送。

如果路由表的记录有重复/有冲突呢,这时候如何选择路径呢?

答:路由表记录有优先级别。一般来说,Windows操作系统的路由表记录,如果是重复的话,以后来加入的记录为准,而某些操作系统,象linux/FreeBSD是不允许加入重复的路由表记录的;

如果是专用的路由器,有路由选择算法,一般来说,到达网络上的某一点的路径是可以有很多条的。路由选择算法可以确定“最好的一条路径”,这条路径要么是延时最小的,要么是通讯费用最低的,要么是带宽最高的,要么是跳点最小的——究竟是如何选择,就看路由器的管理员如何配置了。

对于客户端如果绑定INADDR_ANY,情况类似。对于TCP而言,在connect()系统调用时将其绑定到一具体的IP地址。选择的依据是该地址所在子网到目标地址是可达的(reachable). 这时通过getsockname()系统调用就能得知具体使用哪一个地址。对于UDP而言, 情况比较特殊。即使使用connect()系统调用也不会绑定到一具体地址。这是因为对UDP使用connect()并不会真正向目标地址发送任何建立连接的数据,也不会验证到目标地址的可达性。它只是将目标地址的信息记录在内部的socket数据结构之中,供以后使用。只有当调用sendto()/send()时,由系统内核根据路由表决定由哪一个地址(网卡)发送UDP packet.

P.S.

-----------------------------------------------------------------------------

在IP层中有一个路由表:

在MSDOS窗口可以运行命令:netstat -r

来显示路由表。根据路由表的条目从指定的网卡发送数据。

ARP缓存用:arp -a

来显示。

通常以太网帧的目的MAC地址,是下一跳的MAC地址。

 

 

在Server端bind本机IP地址和端口的时候,有些程序会使用INADDR_ANY这个地址来取代本机地址。这是为什么呢? 
加了printf把INADDR_ANY打印出来看了一下,居然是零。 
查了一些资料和代码,MAC中INADDR_ANY是定义在in.h中的:

#define INADDR_ANY      (u_int32_t)0x00000000

所以打印出来是零。

那么,这个宏定义到底是什么含义呢? 
这个宏能够让程序员在不知道本机IP地址的情况下,使用它来代表本机所有接口的IP地址。也就是说,使用这个宏作为监听地址的话,不管本机有多少个接口,socket都会监听。 
举个例子,假设一个主机有inter1,inter2,,inter3三个接口,如果一个socket绑定了INADDR_ANY的地址和8000的端口,那么,从客户端过来的一个UDP包到达该主机,不管客户端connect的是inter1,inter2,inter3中的哪个地址,都会被该socket接收到。如果此时主机还要再建立一个新的socket,使用inter1接口和端口8000,将会失败,因为这个端口和地址已经被第一个socket监听了。

上面是接收的情况,那么,发送数据报给客户端的时候呢,到底是用哪个接口发送呢? 
这个就是根据本机路由表的配置情况,选择最合适的路径对应的接口来发送。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: INADDR_ANY是一个特殊的IP地址,用于表示任意IP地址。在网络编程中经常使用此常量作为socket绑定的地址,以监听所有可用的网络接口。 以下是一个使用INADDR_ANY的例子: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define PORT 8080 int main() { int sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("socket creation failed"); exit(EXIT_FAILURE); } struct sockaddr_in servaddr = {0}; servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = INADDR_ANY; servaddr.sin_port = htons(PORT); if (bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) { perror("bind failed"); exit(EXIT_FAILURE); } if (listen(sockfd, 5) < 0) { perror("listen failed"); exit(EXIT_FAILURE); } printf("Server listening on port %d\n", PORT); while (1) { int newsockfd = accept(sockfd, NULL, NULL); if (newsockfd < 0) { perror("accept failed"); exit(EXIT_FAILURE); } char buffer[1024] = {0}; int valread = read(newsockfd, buffer, sizeof(buffer)); printf("Received message: %s\n", buffer); const char *reply = "Hello from server"; write(newsockfd, reply, strlen(reply)); close(newsockfd); } close(sockfd); return 0; } ``` 在此示例中,我们创建了一个TCP socket,并使用INADDR_ANY绑定到所有可用的网络接口。然后我们监听连接请求,并在每个新连接上发送“Hello from server”消息。 ### 回答2: INADDR_ANY是一个用于网络编程中的特殊IP地址,代表系统上所有可用的网络接口地址。当在网络编程中使用INADDR_ANY时,系统会在所有网络接口上监听指定的口,以接收来自任意网络接口的连接。 举个例子来说,一个服务器程序可以通过监听INADDR_ANY来在多个网络接口上接收连接请求。假设服务器程序要监听口号为8080的连接请求,它可以使用下面的代码: ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> int main() { int server_fd; struct sockaddr_in server_addr; // 创建套接字 server_fd = socket(AF_INET, SOCK_STREAM, 0); // 设置服务器地址结构 server_addr.sin_family = AF_INET; server_addr.sin_port = htons(8080); server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 绑定套接字到指定地址bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)); // 监听连接请求 listen(server_fd, 5); printf("服务器启动,监听口8080...\n"); while (1) { // 接收连接请求 int client_fd; struct sockaddr_in client_addr; socklen_t client_addr_len = sizeof(client_addr); client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_addr_len); // 处理连接请求 printf("有客户连接到服务器,IP地址:%s,口号:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); // 关闭连接 close(client_fd); } // 关闭套接字 close(server_fd); return 0; } ``` 在上面的例子中,服务器程序创建了一个套接字,并将其绑定到INADDR_ANY和口号8080上。这样,服务器程序就可以接受来自任意网络接口上的连接请求。当有客户连接到服务器时,服务器程序会打印出客户IP地址口号,并关闭连接。 INADDR_ANY的使用可以使服务器程序适用于多个网络接口,提供更高的灵活性和可扩展性。但需要注意的是,使用INADDR_ANY时要确保服务器程序有足够的安全机制,防止未经授权的连接。 ### 回答3: INADDR_ANY是一个常量宏定义,用于在网络编程中指定服务器绑定的IP地址。当服务器程序需要绑定到本机的所有可用IP地址时,就可以使用INADDR_ANY。 举个例子来说明,假设我们有一个简单的TCP服务器程序,希望能够监听本机上所有的IP地址和一个特定的口。这时候我们可以使用INADDR_ANY来指定绑定的IP地址。 #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> int main() { int server_fd, client_fd, port; struct sockaddr_in server_addr, client_addr; char buffer[1024]; port = 8888; // 创建socket server_fd = socket(AF_INET, SOCK_STREAM, 0); // 设置服务器地址 server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port); server_addr.sin_addr.s_addr = INADDR_ANY; // 绑定socket if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { perror("bind failed"); exit(EXIT_FAILURE); } // 监听 if (listen(server_fd, 3) < 0) { perror("listen failed"); exit(EXIT_FAILURE); } // 等待客户连接 while (1) { printf("Waiting for client...\n"); int client_len = sizeof(client_addr); client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_len); printf("Client connected!\n"); // 接收和发送数据 read(client_fd, buffer, sizeof(buffer)); printf("Received: %s\n", buffer); } return 0; } 在上面的例子中,我们创建了一个TCP服务器,通过socket和bind函数指定服务器的IP地址为INADDR_ANY,表示绑定本机上所有可用的IP地址。然后通过listen函数监听口,等待客户的连接。 这样,服务器程序就可以接受来自任意本机IP地址的客户连接,并进行数据交互。这在某些情况下非常有用,特别是在需要同时监听多个IP地址的服务器应用程序中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

隨意的風

如果你觉得有帮助,期待你的打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值