You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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);
}

代码说明

  1. findAdapterForSocket函数:
    • 调用getsockname获取套接字绑定的本地IP地址
    • 枚举所有适配器的单播IP地址,与本地IP匹配后输出对应适配器信息
  2. 完善了原代码的错误处理逻辑,添加WSACleanup的正确调用,避免资源泄漏
  3. 优化输出格式,清晰区分匹配的目标适配器与所有系统适配器

内容的提问来源于stack exchange,提问作者deltamind106

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 03:53:12