我正在运行Linux和BusyBox的设备中嵌入的应用程序中工作。硬件具有2个通信接口(interface):Wi-Fi和3G。
在每个连接中,应用程序必须首先尝试使用wi-fi进行连接,如果失败,则应用程序将再次使用3G进行尝试。
我强制连接使用选定的接口(interface)像这样绑定(bind)它:

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

static void resolveDns(const char *hostname, struct addrinfo **destInfo)
{
    int err;
    struct addrinfo hints;

    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_DGRAM;

    if ((err = getaddrinfo(hostname, "80", &hints, destInfo)) != 0) {
        fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(err));
        exit(EXIT_FAILURE);
    }

    struct sockaddr_in *addr = (struct sockaddr_in *)((*destInfo)->ai_addr);
    printf("Destination IP: %s\n", inet_ntoa(addr->sin_addr));
}

static void getComInterface(const char *iface, struct ifreq *ifr)
{
    ifr->ifr_addr.sa_family = AF_INET;
    strcpy(ifr->ifr_name, iface);

    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    int err = ioctl(sock, SIOCGIFADDR, ifr);
    close(sock);

    if (err) {
        fprintf(stderr, "ioctl error: %d\n", err);
        exit(EXIT_FAILURE);
    }

    printf("Interface IP: %s\n", inet_ntoa(((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr));
}

int main()
{
    int err;

    struct ifreq ifr;
    getComInterface("wlan0", &ifr);

    struct addrinfo *destInfo;
    resolveDns("www.google.com", &destInfo);

    int s = socket(AF_INET, SOCK_STREAM, 0);
    err = bind(s, &ifr.ifr_addr, sizeof(ifr.ifr_addr));
    if (err) {
        fprintf(stderr, "bind error = %d, %d\n", err, errno);
        exit(EXIT_FAILURE);
    }

    err = connect(s, destInfo->ai_addr, destInfo->ai_addrlen);
    if (err) {
        fprintf(stderr, "connect error = %d, %d \n", err, errno);
        exit(EXIT_FAILURE);
    }

    printf("Ok!\n");

    freeaddrinfo(destInfo);
    close(s);
    return EXIT_SUCCESS;
}

但这不能解决DNS查找中的问题。
有没有一种方法可以强制getaddrinfo使用所选接口(interface)?
或者,甚至更好的是,是否有一种方法可以强制所有连接使用选定的接口(interface)而不断开另一个接口(interface)?
附注:如果您知道如何以更复杂的方式(例如Ubuntu)执行此操作,请分享您的解决方案。
谢谢

最佳答案

恐怕仅通过标准C库就无法做到这一点,
即您需要更改默认网关,并为每个连接设置网关。
请考虑以下伪代码:

  • 系统启动:
  • 通过无线网络建立连接
  • 通过3G
  • 建立连接
  • 将wifi接口(interface)配置为默认网关

  • 在新的连接请求上:
  • 执行DNS查找(通过默认路由进行)
  • 如果成功
  • 保存IP地址以及文件描述符
  • 通过当前网关
  • 的接口(interface)配置到该IP的路由
  • 打开套接字的IP地址,流量将通过给定的接口(interface)

  • 如果没有
  • 将默认网关更改为另一个接口(interface)(3G),然后重试



  • 断开连接时:
  • 通过断开连接的文件描述符
  • 查找IP地址
  • 从路由表
  • 中删除IP
  • 转到“根据新连接请求”(取决于您的应用程序逻辑)


  • 这样,您将能够为新连接更改默认网关,但保留现有连接。
    路由表的更改可以通过Linux Shell命令(例如ip route等)完成。
    它们可以通过system从C启动,例如system( "ip route show" );您也可以编写逻辑更复杂的脚本,然后从C代码启动它们。
    但是,此解决方案存在一个缺陷,通常,如果您当前的接口(interface)没有Internet连接,
    这意味着使用此接口(interface)的所有连接最终可能会失败。

    关于c - 如何选择用于执行主机名查找的接口(interface),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/63653312/

    10-11 23:02
    查看更多