什么 C 代码将确定开放套接字正在使用的网络适配器?

问题描述 投票:0回答:1

我有一些在 MS Windows 上运行的 C 代码,我正在使用 Microsoft 编译器对其进行编译/链接。该代码打开一个套接字并连接到远程服务器。

我想编写一些代码来确定我的开放套接字正在使用哪个 Windows 网络适配器。我可以使用 Microsoft 的 GetAdaptersAddresses 函数列出系统中的所有网络适配器。在我的系统中列出了 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;
}
c++ c sockets winapi network-programming
1个回答
0
投票

几个人在问题的评论中提出了正确的解决方案,即使用

getsockname()
获取客户端套接字绑定的IP地址,然后将该IP地址与适配器中的
FirstUnicastAddress
进行匹配从
GetAdaptersAddresses()
回来。下面是有效的实现。下面的代码仅适用于 IPv4,但可以轻松扩展以包含 IPv6。

感谢那些在问题中发表评论的人帮助我解决这个问题。

#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;
}
© www.soinside.com 2019 - 2024. All rights reserved.