如何用C代码确定Windows系统中已连接套接字使用的网卡?
确定Windows下已连接套接字使用的网络适配器
问题概述
现有一段运行在Windows系统的C代码,通过Microsoft编译器编译链接,代码会创建TCP套接字并连接到远程服务器。需要编写逻辑确定该已连接套接字正在使用哪个系统网络适配器。目前已能通过GetAdaptersAddresses枚举系统中的12个适配器,但缺少匹配套接字与适配器的实现逻辑。
解决方案
要匹配套接字与对应适配器,核心逻辑分为两步:
- 调用
getsockname获取已连接套接字绑定的本地IP地址 - 遍历
GetAdaptersAddresses枚举的所有适配器,检查每个适配器的单播IP地址列表,找到与本地IP匹配的适配器,即为套接字使用的网卡
修改后的完整代码
#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> #include <string.h> static void enumAdapters(); static void findAdapterForSocket(SOCKET sockfd); int main(int argc,char *argv[]) { WORD ver = MAKEWORD(2,2); WSADATA wsa; SOCKET sockfd; struct sockaddr_in addr; if (WSAStartup(ver, &wsa) != 0) { fprintf(stderr, "WSAStartup failed\n"); exit(1); } if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { fprintf(stderr, "Failed to create socket\n"); WSACleanup(); 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"); closesocket(sockfd); WSACleanup(); exit(1); } if (connect(sockfd, (const struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR) { fprintf(stderr, "Failed connect\n"); closesocket(sockfd); WSACleanup(); exit(1); } printf("Connected successfully. Finding the adapter used by the socket...\n\n"); findAdapterForSocket(sockfd); printf("\nAll system adapters:\n"); enumAdapters(); closesocket(sockfd); WSACleanup(); exit(0); } static void findAdapterForSocket(SOCKET sockfd) { struct sockaddr_in localAddr; int addrLen = sizeof(localAddr); char localIpStr[INET_ADDRSTRLEN]; IP_ADAPTER_ADDRESSES *buf = NULL; ULONG bufsize = 0; IP_ADAPTER_ADDRESSES *ptr; IP_ADAPTER_UNICAST_ADDRESS *unicastAddr; // 获取套接字的本地绑定地址 if (getsockname(sockfd, (struct sockaddr *)&localAddr, &addrLen) == SOCKET_ERROR) { fprintf(stderr, "getsockname failed: %d\n", WSAGetLastError()); return; } inet_ntop(AF_INET, &localAddr.sin_addr, localIpStr, INET_ADDRSTRLEN); printf("Socket is bound to local IP: %s\n", localIpStr); // 获取适配器地址缓冲区大小 GetAdaptersAddresses(AF_INET, 0, NULL, buf, &bufsize); buf = (IP_ADAPTER_ADDRESSES *)malloc(bufsize); if (!buf) { fprintf(stderr, "Failed to allocate memory for adapters\n"); return; } if (GetAdaptersAddresses(AF_INET, 0, NULL, buf, &bufsize) != NO_ERROR) { fprintf(stderr, "Failed to get adapters\n"); free(buf); return; } // 遍历适配器,匹配本地IP for (ptr = buf; ptr != NULL; ptr = ptr->Next) { unicastAddr = ptr->FirstUnicastAddress; while (unicastAddr != NULL) { if (unicastAddr->Address.lpSockaddr->sa_family == AF_INET) { struct sockaddr_in *adapterIp = (struct sockaddr_in *)unicastAddr->Address.lpSockaddr; char adapterIpStr[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &adapterIp->sin_addr, adapterIpStr, INET_ADDRSTRLEN); if (strcmp(localIpStr, adapterIpStr) == 0) { printf("\nMatching adapter found:\n"); printf("Adapter #%d %s\n", (int)ptr->IfIndex, ptr->AdapterName); printf(" Friendly Name: %wS\n", ptr->FriendlyName); printf(" Description: %wS\n", ptr->Description); free(buf); return; } } unicastAddr = unicastAddr->Next; } } printf("\nNo matching adapter found for local IP %s\n", localIpStr); free(buf); } static void enumAdapters() { IP_ADAPTER_ADDRESSES *buf = NULL; ULONG bufsize = 0; IP_ADAPTER_ADDRESSES *ptr; GetAdaptersAddresses(AF_INET, 0, NULL, buf, &bufsize); buf = (IP_ADAPTER_ADDRESSES *)malloc(bufsize); if (!buf) { fprintf(stderr, "Failed to allocate memory for adapters\n"); return; } if (GetAdaptersAddresses(AF_INET, 0, NULL, buf, &bufsize) != NO_ERROR) { fprintf(stderr, "Failed to get adapters\n"); free(buf); return; } for (ptr = buf; ptr != NULL; ptr = ptr->Next) { printf("\nAdapter #%d %s\n", (int)ptr->IfIndex, ptr->AdapterName); printf(" Friendly Name: %wS\n", ptr->FriendlyName); printf(" Description: %wS\n", ptr->Description); } free(buf); }
代码说明
findAdapterForSocket函数:- 调用
getsockname获取套接字绑定的本地IP地址 - 枚举所有适配器的单播IP地址,与本地IP匹配后输出对应适配器信息
- 调用
- 完善了原代码的错误处理逻辑,添加
WSACleanup的正确调用,避免资源泄漏 - 优化输出格式,清晰区分匹配的目标适配器与所有系统适配器
内容的提问来源于stack exchange,提问作者deltamind106
相关产品推荐
相关产品推荐

