绑定到两个本地IP失败

时间:2013-12-17 07:43:39

标签: c sockets tcp network-programming bind

我有两个无线适配器,一个USB适配器和一个内置于笔记本电脑中。

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

然而,当我在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

我现在采取不同的方法,但我仍然没有使用这两种网络......

1 个答案:

答案 0 :(得分:1)

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

在第一次连接之前,通过“wlp11s0u1”,通过该接口将路由设置为“213.112.225.102”。     route add -host 213.112.225.102 gw 1​​92.168.0.1 dev wlp11s0u1(或GW IP)

然后,在连接第二次之前,通过“wlp10s0”设置路线:     route add -host 213.112.225.102 gw 1​​92.168.2.1 dev wlp10s0(或相应的网关)

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

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


编辑: 我也试过使用Loose source route选项,但由于某种原因它对我不起作用,也许我的路由器不允许使用该IP选项。如果你有兴趣,我可以把代码传给你。

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