单网卡多IP导致的socket connect 10060超时错误
问题:
接管别人代码时遗留的一个bug,在win7下,给一个网卡设置多个ip时,发现无法连接上服务器了。XP下就不会,这多个ip为192.168.1.127,172.1.1.13,10.0.0.1。
复现过程:
复现的过程中我的服务器ip为192.168.1.128,子网掩码255.255.255.0,默认网关为192.168.1.128(服务器不需要联网,所以就这么设置了)。
客户端按照bug说明设置了对应的3个IP。
发现无法复现,然后和测试沟通要求重现,发现他那边设置这样的IP是会出现的。因此比较了下他的服务器IP和我的服务器IP的区别,竟然是默认网关的问题,设置成192.168.1.1就能复现了。(后来发现设置成其他的也可以)。
解决过程:
首先恶补了一下IP、子网掩码、网关的知识。(都还给老师了)(socket技术也不是很熟悉)
分析的话还是从客户端IP开始,首先3个IP中肯定要存在的是192.168.1.127,因为只有这个IP和服务器同网段,其他两个都是不同网段的,并且刚好占据了A、B、C三类IP。于是试着去掉172网段的IP,发现也会复现。
OK,那基本确定就是因为存在一个不同网段的IP导致连接不上服务器了,于是去看源代码,跟踪发现是在调用getaddrinfo时,传入本主机名称,返回的IP列表中存在两个IP,但是代码里面默认就只使用第一个,这win7下第一个刚好是10.0.0.1,当然就无法和192.168.1.128的服务器通信了。测试了下XP下刚好第一个IP是和服务器同网段的,所以就能通信。(不过这里有个疑问就是服务器默认网关设置成192.168.1.128时仍然能通信,这是为什么?)
因为后面调用connect的地方和getaddrinfo的地方不在同一个层级,而且都已经经过了封装,想要将返回的IP列表全部返回到connect的地方会牵涉到比较大的改动,我比较担心引发新的BUG。所以决定在返回Ip给connect使用之前就过滤出和服务器IP在同一网段的IP。
这里是将服务器IP传进去作为一个参照对象。将返回的IP列表中的IP全部转换成unsigned long类型,然后和服务器IP做差,差值最小的就是最接近服务器IP的(认为是和服务器IP同网段的)。要注意的是,inet_addr函数返回的unsigned long是将高段的值放置在末尾的,所以这里调用了ntohl函数将unsigned long逆序一遍。
代码片段如下:
if ( SOCKET_ERROR != getaddrinfo(pstrHost, pstrService, &aiHints, &aiList) && ( aiList != 0 ))
{
// 优先匹配在同一网段的IP地址来使用
ADDRINFO *aiUse = aiList;
if(NULL != aiUse->ai_next && NULL != pszRemote && AF_INET == nFamily) // 只支持ip4的
{
char szAddress[MAX_PATH] = { 0 };
ADDRINFO* aiCrt = aiUse;
unsigned long lulMinimumDiff = 0xffffffff;
unsigned long llRemote = ntohl(inet_addr(pszRemote));
unsigned long llCrt = 0;
unsigned long llDiff = 0;
while(NULL != aiCrt)
{
// 转换成数值,差值最小的就是ip最接近的
const void* addr = &((const sockaddr_in*)aiCrt->ai_addr)->sin_addr;
if (inet_ntop(nFamily, addr, szAddress, MAX_PATH) != NULL)
{
llCrt = ntohl(inet_addr(szAddress));
if(llCrt > llRemote)
llDiff = llCrt - llRemote;
else
llDiff = llRemote - llCrt; if(llDiff < lulMinimumDiff)
{
lulMinimumDiff = llDiff;
aiUse = aiCrt;
}
} aiCrt = aiCrt->ai_next;
}
}
ADDRINFO ai = { 0 };
ai.ai_addr = sockAddr;
memcpy(ai.ai_addr, aiUse->ai_addr, aiUse->ai_addrlen);
freeaddrinfo( aiList );
return true;}
单网卡多IP导致的socket connect 10060超时错误的更多相关文章
- Linux 单网卡多 IP 的配置方法
Linux 单网卡多 IP 的配置方法 1 .永久配置的方法: 知道在 Linux 下网卡被称为 eth0,eth1,eth2..... ,所有网卡的配置文件都存储在 /etc/sysconfi ...
- linux单网卡多IP配置
一.仅一个网卡的情况下,可以让该机器可以通过多个IP被访问,或隐藏常用IP,让他人访问其临时IP. 1.如果临时性的增加一个IP(重启机器或network服务后,丢失),可以使用ifconfig命令 ...
- 如何在centos上配置802.1Q VLAN标记,linux单网卡多vlan多网段Ip配置案例
介绍 VLAN使将大型网络分成较小且易于管理的网络成为可能.802.1Q是所有供应商都在其网络设备中实施的标准.某些交换机能够将多个VLAN分配给单个网络端口.使用此功能,您可以将多个VLAN分配给单 ...
- centos linux系统日常管理复习 CPU物理数逻辑核数,iftop ,iotop ,sar ,ps,netstat ,一网卡多IP,mii-tool 连接,ethtool速率,一个网卡配置多个IP,mii-tool 连接,ethtool速率 ,crontab备份, 第十八节课
centos linux系统日常管理复习 物理CPU和每颗CPU的逻辑核数,uptime ,w,vmstat,iftop ,iotop ,sar ,ps,netstat ,一个网卡配置多个IP,mii ...
- Linux多网卡多IP配置
echo "210 local100" >> /etc/iproute2/rt_tables echo "220 local200" >> ...
- Ubuntu下单网卡多IP地址的配置
删除用户默认配置文件 由于在默认清空下,配置文件是系统自动生成的用户设备配置文件保存在/etc/udev/rule.d/下面:# cp /etc/udev/rule.d /etc/udev/rule. ...
- LINUX一网卡多IP设置
方法1:少量IP手动绑定(这里以绑定IP到eth0为例,其它网卡的话修改相应的文件名即可) 1.复制ifcfg-eth0的网卡配置文件并改名为ifcfg-eth0:0 [root@akinlau /] ...
- 配置多网卡多IP的方式
[root@web01 conf.d]# cat ip.conf server { listen 10.0.0.7:80; server_name _; location ...
- 一块网卡多个IP实现
////////////////////////////写在前面//////////////////////////////////////////// 需要注意,这里我们是一块网卡多个IP,而并非是 ...
随机推荐
- struts2在web.xml中配置详情
web.xml是web应用中载入有关servlet信息的重要配置文件,起着初始化servlet,filter等web程序的作用. 通常,全部的MVC框架都须要Web应用载入一个核心控制器.那採取什么方 ...
- 再探java基础——零碎基础知识整理
1.java是解释型语言.java虚拟机能实现一次编译多次运行. 2.JDK(java software Development kit 软件开发包),JRE(java Runtime Environ ...
- linux怎么给一个普通用户reboot权限?
分四种情况讨论:1.让任何人(包括根本不拥有系统帐号的人)都可以通过控制台reboot在/etc/inittab文件中保留ca::ctrlaltdel:/sbin/shutdown -t3 -r no ...
- HashSet与HashMap
HashSet底层由HashMap实现 Hash表:存放链表表头的数组 HashSet的值存放于HashMap的key上,而HashMap的value统一为PRESENT(private static ...
- 一个简单的Verilog计数器模型
一个简单的Verilog计数器模型 功能说明: 向上计数 向下计数 预装载值 一.代码 1.counter代码(counter.v) module counter( input clk, input ...
- Android集成Mina NIO Socket
Mina简介 Apache MINA(Multipurpose Infrastructure 多功能框架 for Network Applications) 是 Apache 组织一个较新的项目,它为 ...
- ckeditor常用设置
1.首先下载ckeditor放入自己的项目WebRoot目录下 2.在自己的页面中引入需要的js库 3.在界面中书写多行文本域 必须要有name或者id属性 不然没有效果显示 4.修改ckedito ...
- mssql SUBSTRING和charindex的用法
在工作中用到的例子: select * FROM [CSGDC.DataETLDB].[dbo].[StrategiesList] where strategy_name like '%基建系统%' ...
- Ubuntu 11.10开启root用户登陆
以管理员身份运行 #sudo gedit /etc/lightdm/lightdm.conf 将里面改成 "autologin-user=root" 就可以以root用户登录了
- 单点登录CAS使用记(二):部署CAS服务器以及客户端
CAS-Server下载地址:https://www.apereo.org/projects/cas/download-cas CAS-Client下载地址:http://developer.jasi ...