问题:

接管别人代码时遗留的一个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超时错误的更多相关文章

  1. Linux 单网卡多 IP 的配置方法

     Linux 单网卡多 IP 的配置方法 1 .永久配置的方法: 知道在 Linux 下网卡被称为 eth0,eth1,eth2..... ,所有网卡的配置文件都存储在 /etc/sysconfi ...

  2. linux单网卡多IP配置

    一.仅一个网卡的情况下,可以让该机器可以通过多个IP被访问,或隐藏常用IP,让他人访问其临时IP. 1.如果临时性的增加一个IP(重启机器或network服务后,丢失),可以使用ifconfig命令 ...

  3. 如何在centos上配置802.1Q VLAN标记,linux单网卡多vlan多网段Ip配置案例

    介绍 VLAN使将大型网络分成较小且易于管理的网络成为可能.802.1Q是所有供应商都在其网络设备中实施的标准.某些交换机能够将多个VLAN分配给单个网络端口.使用此功能,您可以将多个VLAN分配给单 ...

  4. 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 ...

  5. Linux多网卡多IP配置

    echo "210 local100" >> /etc/iproute2/rt_tables echo "220 local200" >> ...

  6. Ubuntu下单网卡多IP地址的配置

    删除用户默认配置文件 由于在默认清空下,配置文件是系统自动生成的用户设备配置文件保存在/etc/udev/rule.d/下面:# cp /etc/udev/rule.d /etc/udev/rule. ...

  7. LINUX一网卡多IP设置

    方法1:少量IP手动绑定(这里以绑定IP到eth0为例,其它网卡的话修改相应的文件名即可) 1.复制ifcfg-eth0的网卡配置文件并改名为ifcfg-eth0:0 [root@akinlau /] ...

  8. 配置多网卡多IP的方式

    [root@web01 conf.d]# cat ip.conf server {     listen 10.0.0.7:80;     server_name _;       location ...

  9. 一块网卡多个IP实现

    ////////////////////////////写在前面//////////////////////////////////////////// 需要注意,这里我们是一块网卡多个IP,而并非是 ...

随机推荐

  1. android开发4:Android布局管理器1(线性布局,相对布局RelativeLayout-案例)

    控件类概述 View 可视化控件的基类 属性名称 对应方法 描述 android:background setBackgroundResource(int) 设置背景 android:clickabl ...

  2. tomcat安全配置之禁用Directory Listing

    什么是Directory Listing?通俗点讲,就是在webapp的目录下如果没有放置index.html或者类似的文件,如果从IE或者其它浏览器文章这个路径时,会惊喜的发现这个目录下的文件列表被 ...

  3. 第一篇!in和exists性能比较和使用

    首先,先看下in和exists的区别: in 是把外表和内表作hash 连接: exists是对外表作loop循环,每次loop循环再对内表进行查询. 普遍的观点是exists比in效率高的.但是这不 ...

  4. [转] 强大的python字符串解析

    1.python字符串通常有单引号('...').双引号("...").三引号("""...""")或('''...'' ...

  5. HDU 1199 - Color the Ball 离散化

    [题意]现在有几个球排成一排,编号从1开始,开始时所有球为黑色,现在有n(<=2000)次操作,每次操作将l[i]至r[i](均在int范围)的球凃成颜色c[i](黑色'b'或白色'w'),然后 ...

  6. 简单dp --- HDU1248寒冰王座

    题目链接 这道题也是简单dp里面的一种经典类型,递推式就是dp[i] = min(dp[i-150], dp[i-200], dp[i-350]) 代码如下: #include<iostream ...

  7. 关于禁止在 .NET Framework 中执行用户代码。启用 "clr enabled" 配置选项

    这个问题是我新装好sql2008r2以后,我把服务器上的数据库还原到本地,取代码里跟踪测试的时候,出现的这个问题. 然后我在网上找了之后在sql里直接新建查询执行如下语句: exec sp_confi ...

  8. querydsl的好处

    http://www.querydsl.com/ 封装了很多访问不同数据层平台的方法,提供统一的通用框架(统一的书写格式,以一种通用的API方式来构建查询).便于抽成统一数据层,昨晚底层,以后其他模块 ...

  9. HTML入门学习

    html 基本结构    <!DOCTYPE html> ----------------声明文档的解析类型, 避免浏览器的怪异模式<html> --------------- ...

  10. mysql死锁--源于外键关联

    死锁 存在于行级锁 存在的条件 1.资源只能同时被一个线程占有 2.资源占有不能被强制剥夺 3.请求和保持占有(在请求占有资源的同时能保持现有资源的占有) 4.死循环(一般做程序的人最关注的点) 一到 ...