草庐IT

c - 绑定(bind)到两个本地 IP 失败

coder 2023-09-19 原文

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

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

但是,当我在 wireshark 中检查我的网络流量时...我只看到来自一个 ip 的流量!?事实上,尽管我明确绑定(bind)了每个套接字,但我看到了从一个 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 
}
*/

那么,为什么绑定(bind)不绑定(bind)!?

编辑:

好的,感谢这篇旧帖子:Multiple Ethernet Interfaces - How to create a separate network and access from C code

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

最佳答案

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

在第一次连接之前,通过“wlp11s0u1”,您通过该接口(interface)将路由设置为“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() 函数来运行“路由”命令。

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


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

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

关于c - 绑定(bind)到两个本地 IP 失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20628590/

有关c - 绑定(bind)到两个本地 IP 失败的更多相关文章

  1. ruby - 使用 C 扩展开发 ruby​​gem 时,如何使用 Rspec 在本地进行测试? - 2

    我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当

  2. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  3. ruby - ruby 中的 TOPLEVEL_BINDING 是什么? - 2

    它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput

  4. ruby - 即使失败也继续进行多主机测试 - 2

    我已经构建了一些serverspec代码来在多个主机上运行一组测试。问题是当任何测试失败时,测试会在当前主机停止。即使测试失败,我也希望它继续在所有主机上运行。Rakefile:namespace:specdotask:all=>hosts.map{|h|'spec:'+h.split('.')[0]}hosts.eachdo|host|begindesc"Runserverspecto#{host}"RSpec::Core::RakeTask.new(host)do|t|ENV['TARGET_HOST']=hostt.pattern="spec/cfengine3/*_spec.r

  5. ruby - 从 Ruby 中的主机名获取 IP 地址 - 2

    我有一个存储主机名的Ruby数组server_names。如果我打印出来,它看起来像这样:["hostname.abc.com","hostname2.abc.com","hostname3.abc.com"]相当标准。我想要做的是获取这些服务器的IP(可能将它们存储在另一个变量中)。看起来IPSocket类可以做到这一点,但我不确定如何使用IPSocket类遍历它。如果它只是尝试像这样打印出IP:server_names.eachdo|name|IPSocket::getaddress(name)pnameend它提示我没有提供服务器名称。这是语法问题还是我没有正确使用类?输出:ge

  6. ruby - 是否可以覆盖 gemfile 进行本地开发? - 2

    我们的git存储库中目前有一个Gemfile。但是,有一个gem我只在我的环境中本地使用(我的团队不使用它)。为了使用它,我必须将它添加到我们的Gemfile中,但每次我checkout到我们的master/dev主分支时,由于与跟踪的gemfile冲突,我必须删除它。我想要的是类似Gemfile.local的东西,它将继承从Gemfile导入的gems,但也允许在那里导入新的gems以供使用只有我的机器。此文件将在.gitignore中被忽略。这可能吗? 最佳答案 设置BUNDLE_GEMFILE环境变量:BUNDLE_GEMFI

  7. ruby - 这两个 Ruby 类初始化定义有什么区别? - 2

    我正在阅读一本关于Ruby的书,作者在编写类初始化定义时使用的形式与他在本书前几节中使用的形式略有不同。它看起来像这样:classTicketattr_accessor:venue,:datedefinitialize(venue,date)self.venue=venueself.date=dateendend在本书的前几节中,它的定义如下:classTicketattr_accessor:venue,:datedefinitialize(venue,date)@venue=venue@date=dateendend在第一个示例中使用setter方法与在第二个示例中使用实例变量之间是

  8. ruby-on-rails - 创建 ruby​​ 数据库时惰性符号绑定(bind)失败 - 2

    我正在尝试在Rails上安装ruby​​,到目前为止一切都已安装,但是当我尝试使用rakedb:create创建数据库时,我收到一个奇怪的错误:dyld:lazysymbolbindingfailed:Symbolnotfound:_mysql_get_client_infoReferencedfrom:/Library/Ruby/Gems/1.8/gems/mysql2-0.3.11/lib/mysql2/mysql2.bundleExpectedin:flatnamespacedyld:Symbolnotfound:_mysql_get_client_infoReferencedf

  9. ruby - 正则表达式在哪个位置失败? - 2

    我需要一个非常简单的字符串验证器来显示第一个符号与所需格式不对应的位置。我想使用正则表达式,但在这种情况下,我必须找到与表达式相对应的字符串停止的位置,但我找不到可以做到这一点的方法。(这一定是一种相当简单的方法……也许没有?)例如,如果我有正则表达式:/^Q+E+R+$/带字符串:"QQQQEEE2ER"期望的结果应该是7 最佳答案 一个想法:你可以做的是标记你的模式并用可选的嵌套捕获组编写它:^(Q+(E+(R+($)?)?)?)?然后你只需要计算你获得的捕获组的数量就可以知道正则表达式引擎在模式中停止的位置,你可以确定匹配结束

  10. ruby - 具有两个参数的 block - 2

    我从用户Hirolau那里找到了这段代码:defsum_to_n?(a,n)a.combination(2).find{|x,y|x+y==n}enda=[1,2,3,4,5]sum_to_n?(a,9)#=>[4,5]sum_to_n?(a,11)#=>nil我如何知道何时可以将两个参数发送到预定义方法(如find)?我不清楚,因为有时它不起作用。这是重新定义的东西吗? 最佳答案 如果您查看Enumerable#find的文档,您会发现它只接受一个block参数。您可以将它发送两次的原因是因为Ruby可以方便地让您根据它的“并行赋

随机推荐