socket通信,客户端绑定本地ip为INADDR_ANY、端口为0的意义

本文主要介绍了INADDR_ANY和INADDR_NONE的区别。INADDR_NONE代表无效IP地址,INADDR_ANY指定地址为0.0.0.0,即不确定地址。socket绑定INADDR_ANY时监听0.0.0.0地址,只绑定端口让路由表决定传到哪个ip,还说明了其在服务器和客户端的应用情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

INADDR_ANY 和INADDR_NONE区别

INADDR_NONE 是个宏定义,代表IpAddress 无效的IP地址。
查Winsock2.h得到如下代码:
#define INADDR_NONE 0xffffffff
#define INADDR_ANY (u_long)0x00000000

socket绑定的ip为INADDR_ANY 的说明

socket INADDR_ANY 监听0.0.0.0地址 socket只绑定端口让路由表决定传到哪个ip

其中INADDR_ANY就是指定地址为0.0.0.0的地址,这个地址事实上表示不确定地址,或“所有地址”、“任意地址”。
如果指定ip地址为通配地址(INADDR_ANY),那么内核将等到套接字已连接(TCP)或已在套接字上发出数据报时才选择一个本地IP地址。
一般情况下,如果你要建立网络服务器,则你要通知服务器操作系统:请在某地址 xxx.xxx.xxx.xxx上的某端口 yyyy上进行侦听,并且把侦听到的数据包发送给我。这个过程,你是通过bind()系统调用完成的。——也就是说,你的程序要绑定服务器的某地址,或者说:把服务器的某地址上的某端口占为已用。服务器操作系统可以给你这个指定的地址,也可以不给你。

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

具体一点:

比如你的机器有三个ip   
  192.168.1.1   
  202.202.202.202   
  61.1.2.3    
  如果你serv.sin_addr.s_addr=inet_addr("192.168.1.1");      
  然后监听100端口   
  这时其他机器只有connect   192.168.1.1:100才能成功。   
  connect   202.202.202.202:100和connect   61.1.2.3:100都会失败。    
  如果serv.sin_addr.s_addr=htonl(INADDR_ANY);   的话,无论连接哪个ip都可以连上的,只要是往这个端口发送的所有ip都能连上。
    对于客户端如果绑定INADDR_ANY,情况类似。对于TCP而言,在connect()系统调用时将其绑定到一具体的IP地址。选择的依据是该地址所在子网到目标地址是可达的(reachable).这时通过getsockname()系统调用就能得知具体使用哪一个地址。    对于UDP而言,情况比较特殊。即使使用connect()系统调用也不会绑定到一具体地址。这是因为对UDP使用connect()并不会真正向目标地址发送任何建立连接的数据,也不会验证到目标地址的可达性。它只是将目标地址的信息记录在内部的socket数据结构之中,共以后使用。只有当调用sendto()/send()时,由系统内核根据路由表决定由哪一个地址(网卡)发送UDP packet.

	//客户端绑定本地地址
	if(strlen(m_strMyIP) > 0 || m_nMyPort > 0)
	{
		struct sockaddr_in sin;
		memset (&sin, 0, sizeof(sin));
		sin.sin_family = AF_INET;
        //如果端口号大于0,绑定自己的端口号,否者绑定端口号为0
		if(m_nMyPort > 0)
			sin.sin_port = htons(m_nMyPort);
		else
			sin.sin_port = htons(0);  
        //如果IP大于0,绑定自己的IP,否者绑定IP为0.0.0.0
		if(strlen(m_strMyIP) > 0)
        {
			sin.sin_addr.s_addr = inet_addr(m_strMyIP);
        }	
		else
        {
			sin.sin_addr.s_addr = htonl(INADDR_ANY);
        }

		if (sin.sin_addr.s_addr == INADDR_NONE)
        {
			sin.sin_addr.s_addr = htonl(INADDR_ANY);
        }


#ifdef 1  
		if (bind(m_sockfd, &sin, sizeof(sin)) == -1)   
#else  
		if (bind(m_sockfd, (struct sockaddr*)&sin, sizeof(sin)) == -1)  
#endif  
		{
            close(m_sockfd);
            s = INVALID_SOCKET; 
			cout<<"bind local socket fail"<<enld;
			return false;
		}
	}


P.S.

-----------------------------------------------------------------------------
在IP层中有一个路由表:
在MSDOS窗口可以运行命令:netstat -r 
来显示路由表。根据路由表的条目从指定的网卡发送数据。
ARP缓存用:arp -a 来显示。
通常以太网帧的目的MAC地址,是下一个的MAC地址。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值