我正在运行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库就无法做到这一点,
即您需要更改默认网关,并为每个连接设置网关。
请考虑以下伪代码:
这样,您将能够为新连接更改默认网关,但保留现有连接。
路由表的更改可以通过Linux Shell命令(例如
ip route
等)完成。它们可以通过
system
从C启动,例如system( "ip route show" );
您也可以编写逻辑更复杂的脚本,然后从C代码启动它们。但是,此解决方案存在一个缺陷,通常,如果您当前的接口(interface)没有Internet连接,
这意味着使用此接口(interface)的所有连接最终可能会失败。
关于c - 如何选择用于执行主机名查找的接口(interface),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/63653312/