Chinaunix首页 | 论坛 | 博客
  • 博客访问: 270787
  • 博文数量: 84
  • 博客积分: 3186
  • 博客等级: 中校
  • 技术积分: 852
  • 用 户 组: 普通用户
  • 注册时间: 2009-10-15 15:46
文章分类

全部博文(84)

文章存档

2015年(1)

2014年(12)

2011年(29)

2010年(42)

分类: LINUX

2010-07-29 05:59:44

    突如其来的伤风感冒,让我无法适应。高温的天气,即使坐着不动也会冒汗,偏偏又感觉到冷。
    这几天在看Linux下多网卡的资料,因为服务器要工作在多网卡模式下,会涉及到分流的策略。当然,我还没有到研究这个问题的时候,因为距离这个课题还比较远,先要扫清周围的障碍才行。
    多网卡环境下,首先涉及到服务器的监听,设置socket地址为INADDR_ANY可以将所有的网卡的具体端口纳入监听的范围之内,但是,accept到的socket是连接到哪个网卡的,需要在应用层加以区分,因为上层软件支持过代理之类的设置,查了一下尝试用ioctl获取,发现获取的时候需要指定网卡设备名(ifname),显然不可取,因为如果知道了连接哪个网卡,问题会相对简单一些,现在可以根据socket获取某个连接使用的哪个网卡设备。
   accept函数的参数addr可以获取对方的IP信息,但需要填充好sin_family类型。使用getsockname()和getpeername()可以得到本地连接和远程对方的IP,在多网卡环境下测试能够区分开不同的网卡上的连接。因此,由应用程序管理不同的网卡上的连接以及做相关的均衡, 是一种思路。
    对不同的网卡,采用不同的监听线程,即监听线程与网卡绑定,会绕过上面的问题,但那样会打破原先的程序架构,不到不得已,先不这样做。
    另一个问题是网关的设置,现在的问题是似乎只一个网卡的网关生效,系统默认按照default的路由,另一个网卡上的数据包也会走默认的网关,很多时候出不去。route设置可以针对不同的网卡设备添加相应的default网关,需要进一步实验,查资料。
    跟踪了一下netstat的代码,发现其统计连接的方式是通过读取/proc/net/下的tcp,udp等文件分析得来的,也就是内核最清楚具体连接的双方以及对应的socket。对tcp连接,内核中的实现是通过tcp4_seq_show(版本2.6.11)将相关的信息输出到proc中的。也就是说,如果将这个函数hack,netstat将得不到tcp连接的信息了。ifconfig得到网卡设备的信息是通过读取/proc/net/dev实现的。
    部分测试代码:

/**
  *This program is used for testing the network ip.
  */

#include <sys/types.h> /* See NOTES */
#include <stdio.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <errno.h>
#include <time.h>
#include <asm/ioctls.h>
#include <signal.h>
#include <linux/if.h>
#include <linux/sockios.h>

#define MAX_LISTENERS 30
#define DBG_SERVER
#ifdef DBG_SERVER
#define DBG(x) x
#else
#define DBG(x)
#endif

int get_src_bindip(int _iSocket)
{
    struct ifreq if_req;
    int iIP = -1;
    int iRet = -1;
    struct sockaddr_in sin_a;

    memset(&if_req, 0, sizeof(struct ifreq));
    strncpy(if_req.ifr_name, "eth0", 6);
    if_req.ifr_name[4] = 0;
    if(_iSocket > 0)
    {
       iRet = ioctl(_iSocket, SIOCGIFADDR, &if_req);
     if(iRet < 0)
     {
         printf("Error %d %s\n", errno, strerror(errno));
         return iRet;
     }
    }
    memcpy(&sin_a, &if_req.ifr_addr, sizeof(sin_a));
    printf("ip is %s \n", inet_ntoa(sin_a.sin_addr));
    return 0;
}

int get_dst_ip(int _iSocket)
{
    struct ifreq if_req;
    int iIP = -1;
    int iRet = -1;
    struct sockaddr_in sin_a;
    
    memset(&if_req, 0, sizeof(struct ifreq));
    strncpy(if_req.ifr_name, "eth0", 6);
    if(_iSocket > 0)
    {
            iRet = ioctl(_iSocket, SIOCGIFDSTADDR, &if_req);
     if(iRet < 0)
     {
         printf("Error %d %s\n", errno, strerror(errno));
         return iRet;
     }
    }
    memcpy(&sin_a, &if_req.ifr_addr, sizeof(sin_a));
    printf("ip is %s \n", inet_ntoa(sin_a.sin_addr));
    
    return 0;
}

int main(int argc, char * argv[])
{
    
    struct sockaddr_in sin1;
    int size;
    struct timeval nTimeout;
    int iServerFD = -1;
    int iConnectFD = -1;
    int iSrcAddr = -1;
    int iDstAddr = -1;
    char cAddr[16] = {0};
    char cMask[16] = {0};
        
    iServerFD = socket(AF_INET, SOCK_STREAM, 0);
    if(iServerFD < 0)
    {
        DBG(printf("Create socket error!\n"));
    return iServerFD;
    }
    
    
    sin1.sin_family = AF_INET;
    sin1.sin_port = htons(8000);
    sin1.sin_addr.s_addr = htonl(INADDR_ANY);

    if(bind(iServerFD, (struct sockaddr *)&sin1, sizeof(struct sockaddr_in)) < 0)
    {
    DBG(printf("Bind error!\n"));
    return -1;
    }

    if( listen(iServerFD, MAX_LISTENERS) < 0)
    {
    DBG(printf("Listen failed!\n"));
    return -1;
    }
    
    printf("Start to listen....\n");

    if((iConnectFD = accept(iServerFD, (struct sockaddr *)&sin1, &size)) < 0)
    {
    DBG(printf("Accept failed!\n"));
    return -1;
    }
    DBG(printf("got the client connected %s!\n", inet_ntoa(sin1.sin_addr)));
    getpeername(iConnectFD, (struct sockaddr *)&sin1, &size);
    DBG(printf("got the client connected %s!\n", inet_ntoa(sin1.sin_addr)));
    getsockname(iConnectFD, (struct sockaddr *)&sin1, &size);
    DBG(printf("The IP %s!\n", inet_ntoa(sin1.sin_addr)));

    iSrcAddr = get_src_bindip(iConnectFD);
    iDstAddr = get_dst_ip(iConnectFD);

    printf("The src is 0x%x dst is 0x%x\n", iSrcAddr, iDstAddr);

    close(iServerFD);
    close(iConnectFD);
    
    return 0;
}


阅读(2721) | 评论(0) | 转发(0) |
0

上一篇:华为,摩托

下一篇:ftp的断点上传与下载

给主人留下些什么吧!~~