我有一些C代码运行在MS Windows上,我正在编译/链接与微软编译器. 代码打开一个套接字并连接到远程服务器.

我想编写一些代码来确定我的开放套接字正在使用哪个Windows网络适配器. 我可以使用Microsoft的GetAdaptersDDL函数列出系统中的所有网络适配器. 在我的系统中,列出了12个适配器. 我想写一些C代码来确定哪一个适配器承载了我的开放套接字的通信.

下面是一些工作示例代码,它演示了一个连接的套接字并枚举了网络适配器. 我在Google搜索了一些示例C代码,以确定哪个网络适配器与我的套接字相关联,但没有结果. 谢谢你能提供的任何帮助.

#include <winsock2.h>
#include <ws2tcpip.h>
#include <io.h>
#include <Iphlpapi.h>
#pragma comment(lib,"WS2_32.lib")
#pragma comment(lib,"IPHLPAPI.lib")

#include <stdio.h>
#include <stdlib.h>

static void enumAdapters();

int main(int argc,char *argv[])
{
WORD ver = MAKEWORD(2,2);
WSADATA wsa;
int sockfd;
struct sockaddr_in addr;

    WSAStartup(ver,&wsa);
    if ((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0) {
        fprintf(stderr,"Failed socket\n");
        exit(1);
    }
    addr.sin_family = AF_INET;
    addr.sin_port = htons(80);
    if (inet_pton(AF_INET,"142.250.65.238",&addr.sin_addr) < 0) {
        fprintf(stderr,"Failed inet_pton\n");
        exit(1);
    }
    if (connect(sockfd,(const struct sockaddr *)&addr,sizeof(addr)) < 0) {
        fprintf(stderr,"Failed connect\n");
        exit(1);
    }
    printf("Which of these adapters is my connected socket using?\n\n");
    enumAdapters();
    close(sockfd);
    exit(0);
}


static void enumAdapters()
{
IP_ADAPTER_ADDRESSES _dummy,*ptr,*buf=&_dummy;
ULONG bufsize=0;

    GetAdaptersAddresses(AF_INET,0,NULL,buf,&bufsize);
    buf = (IP_ADAPTER_ADDRESSES *)malloc(bufsize);
    if (GetAdaptersAddresses(AF_INET,0,NULL,buf,&bufsize) != NO_ERROR) {
        fprintf(stderr,"Failed to get adapters\n");
        return;
    }
    for (ptr=buf; ptr!=NULL; ptr=ptr->Next) {
        printf("Adapter #%d %s\n",(int)ptr->IfIndex,ptr->AdapterName);
        printf("    %wS (%wS)\n",ptr->FriendlyName,ptr->Description);
    }
    free(buf); 
    return;
}

推荐答案

几个人在对问题的 comments 中提出了正确的解决方案,即使用getsockname()获取客户端套接字绑定到的IP地址,然后将该IP地址与GetAdaptersAddresses()返回的适配器的FirstUnicastAddress进行匹配. 下面是C的实现. 该代码仅适用于IPv4,但可以很容易地扩展到IPv6.

感谢那些在问题中发表 comments 的人帮助我解决了这个问题.

#include <winsock2.h>
#include <ws2tcpip.h>
#include <io.h>
#include <Iphlpapi.h>
#pragma comment(lib,"WS2_32.lib")
#pragma comment(lib,"IPHLPAPI.lib")
#include <stdio.h>
#include <stdlib.h>

static IP_ADAPTER_ADDRESSES *getAdapterOfSocket(int sockfd,IP_ADAPTER_ADDRESSES **all_adapters);

int main(int argc,char *argv[])
{
WORD ver = MAKEWORD(2,2);
WSADATA wsa;
IP_ADAPTER_ADDRESSES *all_adapters=NULL,*adapter=NULL;
char cbuf[48];
struct sockaddr_in addr;
int sockfd;

    WSAStartup(ver,&wsa);
    if ((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0) {
        fprintf(stderr,"Failed socket\n");
        exit(1);
    }
    addr.sin_family = AF_INET;
    addr.sin_port = htons(80);
    if (inet_pton(AF_INET,"142.250.65.238",&addr.sin_addr) < 0) {
        fprintf(stderr,"Failed inet_pton\n");
        exit(1);
    }
    if (connect(sockfd,(const struct sockaddr *)&addr,sizeof(addr)) < 0) {
        fprintf(stderr,"Failed connect\n");
        exit(1);
    }
    if ((adapter = getAdapterOfSocket(sockfd,&all_adapters)) != NULL) {
        printf("Socket is using adapter index %d\n",adapter->IfIndex);
        printf("    %wS (%wS)\n",adapter->FriendlyName,adapter->Description);
        struct sockaddr_in *sockaddr = (struct sockaddr_in *)adapter->FirstUnicastAddress->Address.lpSockaddr;
        printf("    IP: %s\n",inet_ntop(AF_INET,&sockaddr->sin_addr,cbuf,sizeof(cbuf)));
        printf("    MAC: ");
        for (int n=0; n<adapter->PhysicalAddressLength; n++) {
            printf("%s%02x",n==0?"":"-",(int)adapter->PhysicalAddress[n]);
        }
        printf("\n");
    } else {
        printf("Failed to find adapter used by socket\n");
    }
    if (all_adapters!=NULL) free(all_adapters);
    close(sockfd);
    exit(0);
}


static IP_ADAPTER_ADDRESSES *getAdapterOfSocket(int sockfd,IP_ADAPTER_ADDRESSES **all_adapters)
{
struct sockaddr_in nameaddr;
int nameaddr_len = sizeof(nameaddr);
IP_ADAPTER_ADDRESSES *ptr;
IP_ADAPTER_UNICAST_ADDRESS_LH *addr;
ULONG bufsize=0;
    
    if (getsockname(sockfd,(struct sockaddr *)&nameaddr,&nameaddr_len) < 0) {
        fprintf(stderr,"Failed getsockname\n");
        return NULL;
    }
    GetAdaptersAddresses(AF_INET,0,NULL,NULL,&bufsize);
    *all_adapters = (IP_ADAPTER_ADDRESSES *)malloc(bufsize);
    if (GetAdaptersAddresses(AF_INET,0,NULL,*all_adapters,&bufsize) != NO_ERROR) {
        fprintf(stderr,"Failed to get adapters\n");
        return NULL;
    }
    for (ptr=*all_adapters; ptr!=NULL; ptr=ptr->Next) {
        for (addr=ptr->FirstUnicastAddress; addr!=NULL; addr=addr->Next) {
            struct sockaddr_in *sockaddr = (struct sockaddr_in *)addr->Address.lpSockaddr;
            if (memcmp(&sockaddr->sin_addr,&nameaddr.sin_addr,sizeof(struct in_addr)) == 0) {
                return ptr;
            }
        }
    }
    return NULL;
}

C++相关问答推荐

C中的ATONE会扰乱SEN/CLUTE GMS应用程序中的其他字符串

想了解 struct 指针和空指针转换

了解一些CLIPS原语数据类型

C中的指针增量和减量(*--*++p)

在C++中通过空指针隐式访问常量变量的值

FRIDA-服务器成为端口扫描的目标?

为什么双精度d=flt_max+flt_max;在c语言中得到inf的结果

接受任何参数的函数指针是否与接受不同参数的函数兼容

将变量或参数打包到 struct /联合中是否会带来意想不到的性能损失?

为什么二进制文件的大小不会随着静态数据的大小而增加?

正在try 理解C++中的`正在释放的指针未被分配‘错误

与指针的原始C数组或C++向量<;向量<;双>>;

令人困惑的返回和 scanf 问题相关

C 和 C++ 标准如何告诉您如何处理它们未涵盖的情况?

函数指针作为函数参数 - 应该使用 const 吗?

中位数和众数不正确

如何为avr atmega32微控制器构建C代码,通过光电二极管捕获光强度并通过串行通信传输数据

C/C++编译器可以在编译过程中通过按引用传递来优化按值传递吗?

C Makefile - 如何避免重复提及文件名

C 预处理器中的标记分隔符列表