2013-12-17 48 views
1

我有两个无线适配器,一个USB适配器和一个内置于我的笔记本电脑。绑定到两个本地IP失败

我想能够使用这两个连接。因此,在玩具示例中,我将两个不同的套接字绑定到两个不同的IP地址和端口号,并在每个套接字上调用连接。

但是,当我检查wireshark中的网络流量时......我只能看到来自一个ip的流量!事实上,尽管我明确绑定了每个套接字,但我发现两个调用都需要从一个IP地址进行连接。

这里是我使用的代码:

注意,我还使用非阻塞套接字和选择。我为此已经验证的代码适用于一个互联网连接。

#include <string.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <errno.h> 
#include <sys/socket.h> 
#include <netdb.h> 
#include <arpa/inet.h> 
#include <fcntl.h> 
#include <unistd.h> 
#include <sys/time.h> 
#include <net/if.h> 
#include <sys/ioctl.h> 


int main() { 

    const char * destIp = "213.112.225.102"; 

    const char * ip1 = "192.168.43.1";//"172.31.55.111";//"198.228.228.28"; 
    int portNumber1 = 55555; 
    int sockFd1 = -1; 

    const char * ip2 = "192.168.1.1";//"98.249.5.16"; 
    int portNumber2 = 7777; 
    int sockFd2 = -1; 

    struct sockaddr_in serverAddress; 
    serverAddress.sin_addr.s_addr = inet_pton(AF_INET, "213.112.225.102", &(serverAddress.sin_addr)); 
    serverAddress.sin_port = htons(6985); 

    /////////////////////////////////////////// 
    struct sockaddr * saddr; 
    struct addrinfo hints, * ai, * it; 
    char strportnum[] = "6985"; 
    memset(&hints, '\0', sizeof(hints)); 
    hints.ai_flags = AI_ADDRCONFIG; 
    hints.ai_socktype = SOCK_STREAM; 

    getaddrinfo(destIp, strportnum, &hints, &ai); 

    saddr = ai->ai_addr; 
    saddr->sa_family = AF_INET; 

    it = ai; 
    /////////////////////////////////////////////// 
    //char * opt; 
    int res; 
    long arg; 
    fd_set myset; 
    struct timeval tv; 
    int valopt; 
    socklen_t lon; 
    struct sockaddr_in clientAddress; 
    struct sockaddr_in clientAddress2; 

    printf("it fam == ||%d||, AF_INET == ||%d||\n", it->ai_family, AF_INET); 

    printf("ATTEMPTING SOCKET 1!\n"); 
    //IP 1 CONNECTION----------------------------------------------------------------------------------// 
    if ((sockFd1 = socket(it->ai_family, it->ai_socktype, it->ai_protocol)) != -1) { 


     system("route add -net 213.112.225.102 netmask 255.255.255.255 gw 192.168.43.1 dev wlp10s0"); 

     struct ifreq interface1; 
     memset(&interface1, 0, sizeof(interface1)); 
     strncpy(interface1.ifr_ifrn.ifrn_name, "wlp10s0", IFNAMSIZ); 

     if (setsockopt(sockFd1, SOL_SOCKET, SO_BINDTODEVICE, &interface1, sizeof(interface1)) < 0) { 
      printf("error in set sock opt 1... errno == %d strerror == (%s)\n", errno, strerror(errno)); 

      close(sockFd1); // Error 
      return 1; 
     } 


     clientAddress.sin_family = AF_INET; 
     clientAddress.sin_addr.s_addr = inet_pton(AF_INET, ip1, &(clientAddress.sin_addr)); 
     clientAddress.sin_port = htons(portNumber1); 
     if (bind(sockFd1, (struct sockaddr *) &clientAddress, sizeof(clientAddress)) < 0) { 
      fprintf(stderr, "Error with bind, errno == %d (%s)\n", errno, strerror(errno)); 
     } 



     // Set non-blocking 
     if((arg = fcntl(sockFd1, F_GETFL, NULL)) < 0) { 
      fprintf(stderr, "Error fcntl(..., F_GETFL) (%s)\n", strerror(errno)); 
      return 1; 
     } 
     arg |= O_NONBLOCK; 
     if(fcntl(sockFd1, F_SETFL, arg) < 0) { 
      fprintf(stderr, "Error fcntl(..., F_SETFL) (%s)\n", strerror(errno)); 
      return 1; 
     } 

     printf("ATTEMPTING CONNECTION 2!\n"); 
     // Trying to connect with timeout 
     res = connect(sockFd1, saddr, sizeof(*saddr)); 
     if (res < 0) { 

      if (errno == EINPROGRESS) { 

       fprintf(stderr, "EINPROGRESS in connect() - selecting\n"); 

       do { 

        //Set timeouts 
        tv.tv_sec = 15; 
        tv.tv_usec = 0; 

        FD_ZERO(&myset); 
        FD_SET(sockFd1, &myset); 

        res = select(sockFd1 + 1, NULL, &myset, NULL, &tv); 

        if (res < 0 && errno != EINTR) { 
         fprintf(stderr, "Error connecting %d - %s\n", errno, strerror(errno)); 
        } 
        else if (res > 0) { 

         // Socket selected for write 
         lon = sizeof(int); 
         if (getsockopt(sockFd1, SOL_SOCKET, SO_ERROR, (void *) &valopt, &lon) < 0) { 
          fprintf(stderr, "Error in getsockopt() %d - %s\n", errno, strerror(errno)); 
         } 

         // Check the value returned... 
         if (valopt) { 
          fprintf(stderr, "Error in delayed connection() %d - %s\n", valopt, strerror(valopt)); 
         } 

         break; 
        } 
        else { 
         fprintf(stderr, "Timeout in select() - Cancelling!\n"); 
         break; 
        } 
       } while (1); 
      } 
      else { 
       fprintf(stderr, "Error connecting %d - %s\n", errno, strerror(errno)); 
      } 
     } 
    } 



    printf("ATTEMPTING SOCKET 2!\n"); 
    //IP 2 CONNECTION----------------------------------------------------------------------------------// 
    if ((sockFd2 = socket(it->ai_family, it->ai_socktype, it->ai_protocol)) != -1) { 

     system("route add -net 213.112.225.102 netmask 255.255.255.255 gw 192.168.1.1 dev wlp11s0u1"); 

     struct ifreq interface2; 
     memset(&interface2, 0, sizeof(interface2)); 
     strncpy(interface2.ifr_ifrn.ifrn_name, "wlp11s0u1", IFNAMSIZ); 

     if (setsockopt(sockFd2, SOL_SOCKET, SO_BINDTODEVICE, &interface2, sizeof(interface2)) < 0) { 
      printf("error in set sock opt 2... errno == %d strerror == (%s)\n", errno, strerror(errno)); 
      close(sockFd2); // Error 
      return 1; 
     } 


     clientAddress2.sin_family = AF_INET; 
     clientAddress2.sin_addr.s_addr = inet_pton(AF_INET, ip2, &(clientAddress.sin_addr)); 
     clientAddress2.sin_port = htons(portNumber2); 
     if (bind(sockFd2, (struct sockaddr *) &clientAddress2, sizeof(clientAddress2)) < 0) { 
      fprintf(stderr, "Error with bind (%s)\n", strerror(errno)); 
     } 



     // Set non-blocking 
     if((arg = fcntl(sockFd2, F_GETFL, NULL)) < 0) { 
      fprintf(stderr, "Error fcntl(..., F_GETFL) (%s)\n", strerror(errno)); 
      return 1; 
     } 
     arg |= O_NONBLOCK; 
     if(fcntl(sockFd2, F_SETFL, arg) < 0) { 
      fprintf(stderr, "Error fcntl(..., F_SETFL) (%s)\n", strerror(errno)); 
      return 1; 
     } 

     printf("ATTEMPTING CONNECTION 2!\n"); 
     // Trying to connect with timeout 
     res = connect(sockFd2, saddr, sizeof(*saddr)); 
     if (res < 0) { 

      if (errno == EINPROGRESS) { 

       fprintf(stderr, "EINPROGRESS in connect() - selecting\n"); 

       do { 

        //Set timeouts 
        tv.tv_sec = 15; 
        tv.tv_usec = 0; 

        FD_ZERO(&myset); 
        FD_SET(sockFd2, &myset); 

        res = select(sockFd2 + 1, NULL, &myset, NULL, &tv); 

        if (res < 0 && errno != EINTR) { 
         fprintf(stderr, "Error connecting %d - %s\n", errno, strerror(errno)); 
        } 
        else if (res > 0) { 

         // Socket selected for write 
         lon = sizeof(int); 
         if (getsockopt(sockFd2, SOL_SOCKET, SO_ERROR, (void *) &valopt, &lon) < 0) { 
          fprintf(stderr, "Error in getsockopt() %d - %s\n", errno, strerror(errno)); 
         } 

         // Check the value returned... 
         if (valopt) { 
          fprintf(stderr, "Error in delayed connection() %d - %s\n", valopt, strerror(valopt)); 
         } 

         break; 
        } 
        else { 
         fprintf(stderr, "Timeout in select() - Cancelling!\n"); 
         break; 
        } 
       } while (1); 
      } 
      else { 
       fprintf(stderr, "Error connecting %d - %s\n", errno, strerror(errno)); 
      } 
     } 
    } 

    return 0; 
} 

/* 
ifreq interface; 
memset(&interface, 0, sizeof(interface)); 
strncpy(interface.ifr_ifrn.ifrn_name, "eth1", IFNAMSIZ); 

if (setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, &interface, sizeof(interface)) < 0) { 
    close(sd); // Error 
} 
*/ 

那么,为什么绑定不绑定!

编辑:

好了,感谢这个老帖子:Multiple Ethernet Interfaces - How to create a separate network and access from C code

我采取了不同的方法了,但我还是感到不利用这两个网络...

+0

要查看地址X的响应,您需要发送一个请求来寻址X.如果您只发送请求来寻址Y,X应该从哪里来? –

+0

我不确定你在说什么。我有地址x1和x2,并且我在两个地方都调用了连接。这从x1发送一个tcp数据包到y和x2到y。但相反,他们都来自x1 .... – Ethan

+1

对不起,误读你的问题。你有一个客户端,而不是服务器。在这种情况下,这只是一个路由问题。你可能有一条默认路由通过你的一个接口。发往非本地网络的数据包只能进入该接口。否则,您需要运行路由服务。那些通常不在笔记本电脑上运行,而是在像思科这样的公司生产的大盒子上运行。 –

回答

1

我的天堂没有尝试过,但只是一个想法。没有看过内核代码,也许你可以欺骗内核,但我不确定它是否会起作用。冒着说错话的风险。

在第一次连接之前,通过“wlp11s0u1”,通过该接口将路由设置为“213.112.225.102”。 路由添加-host 213.112.225.102 GW 192.168.0.1开发wlp11s0u1(或GW IP)

然后,连接第二次,通过 “wlp10s0” 之前你设定的路线: 路由添加-host 213.112.225.102 GW 192.168.2.1 dev wlp10s0(或相应的网关)

您可以使用system()函数来运行“route”命令。

如果在连接建立后内核不评估路由,它可能会工作。如果内核评估通过连接套接字发送的每个数据报的路由,它将不起作用。你可以尝试一个简单的解决方案。


编辑: 我尝试使用也松源路由选项,并没有为我工作由于某种原因,也许我的路由器不允许IP选项。如果您有兴趣,我可以通过您的代码。

其他可能性肯定会起作用的是您使用数据包套接字,但您必须添加IP和TCP标头以及管理ARP,IP和TCP算法。这很有趣。

+0

为什么我会将路线设置为213.112.225?这是我连接到的IP地址。 – Ethan

+0

您正在告诉内核,对于发往该IP的数据报,它必须通过上述接口发送数据报。 – rodolk

+1

您正在告诉内核注册到IP 213.112.225.102的数据报,它必须通过上述接口发送数据报。您正试图连接到IP地址213.112.225.102,对不对?我假设你有一个网关(gw)(你必须设置你的网关的IP地址,取代我写的)。再次,我不确定它是否可以工作,但很容易尝试。 – rodolk