我有一些在 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;
}
几个人在问题的评论中提出了正确的解决方案,即使用
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;
}