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

请求总结socket地址结构联合体形式及所用具体地址结构细节

Socket地址结构联合体完整概述

一、联合体的核心作用

Socket API的多数核心函数(如bind()、connect()、recvfrom())要求传入通用的struct sockaddr指针,但不同协议族(IPv4、IPv6、Unix域等)的地址格式差异极大。用联合体封装各类地址结构,既能满足API对通用指针的要求,又能直接访问特定协议的字段,同时节省内存空间。

二、标准联合体的典型形式

以下是C语言中最常用的Socket地址联合体定义,包含主流协议族的地址结构:

#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/un.h>

union sockaddr_union {
    struct sockaddr      sa;    // 通用地址结构(API接口用)
    struct sockaddr_in   sin;   // IPv4专属地址结构
    struct sockaddr_in6  sin6;  // IPv6专属地址结构
    struct sockaddr_un   sun;   // Unix域套接字专属地址结构
};

使用时,通过sa.sa_family字段判断地址族,再直接访问对应联合体成员即可。

三、各成员对应的详细地址结构

1. 通用地址结构 struct sockaddr

这是所有Socket地址结构的基础模板,仅作为API的通用接口使用:

struct sockaddr {
    sa_family_t sa_family;  // 地址族标识(如AF_INET、AF_INET6、AF_UNIX)
    char sa_data[14];       // 可变长度地址数据,不同协议族格式不同
};

注意:sa_data长度仅14字节,无法容纳IPv6或Unix域地址,实际业务中需通过联合体转换为具体结构。

2. IPv4地址结构 struct sockaddr_in

专门用于IPv4协议的地址结构:

struct sockaddr_in {
    sa_family_t sin_family;     // 固定为AF_INET
    in_port_t sin_port;         // 端口号,需用`htons()`转换为网络字节序
    struct in_addr sin_addr;    // IPv4地址结构体
    char sin_zero[8];           // 填充字段,使结构体总大小与`struct sockaddr`一致,通常用`memset`清零
};

// 嵌套的IPv4地址结构体
struct in_addr {
    uint32_t s_addr;            // 32位IPv4地址,需用`htonl()`或`inet_addr()`转换为网络字节序
};

3. IPv6地址结构 struct sockaddr_in6

专门用于IPv6协议的地址结构:

struct sockaddr_in6 {
    sa_family_t sin6_family;    // 固定为AF_INET6
    in_port_t sin6_port;        // 端口号,网络字节序
    uint32_t sin6_flowinfo;     // 流信息,用于QoS控制,通常设为0
    struct in6_addr sin6_addr;  // IPv6地址结构体
    uint32_t sin6_scope_id;     // 作用域ID,使用链路本地地址时需指定对应网络接口索引
};

// 嵌套的IPv6地址结构体
struct in6_addr {
    unsigned char s6_addr[16];  // 128位IPv6地址,网络字节序
};

4. Unix域套接字地址结构 struct sockaddr_un

用于同一主机内的进程间通信:

struct sockaddr_un {
    sa_family_t sun_family;     // 固定为AF_UNIX(或AF_LOCAL)
    char sun_path[108];         // Unix域套接字的文件系统路径,如"/tmp/my_socket"
};

注意:使用后需手动删除sun_path对应的文件,避免下次绑定失败。

四、联合体的实用示例

以recvfrom()接收多协议数据为例,用联合体统一处理不同地址类型:

union sockaddr_union peer_addr;
socklen_t addr_len = sizeof(peer_addr);
char buf[1024];

ssize_t recv_len = recvfrom(sock_fd, buf, sizeof(buf), 0, (struct sockaddr*)&peer_addr, &addr_len);
if (recv_len == -1) {
    perror("recvfrom");
    exit(EXIT_FAILURE);
}

// 根据地址族分支处理
switch (peer_addr.sa.sa_family) {
    case AF_INET:
        printf("来自IPv4:%s:%d\n", 
               inet_ntoa(peer_addr.sin.sin_addr), 
               ntohs(peer_addr.sin.sin_port));
        break;
    case AF_INET6:
        char ipv6_buf[INET6_ADDRSTRLEN];
        inet_ntop(AF_INET6, &peer_addr.sin6.sin6_addr, ipv6_buf, sizeof(ipv6_buf));
        printf("来自IPv6:%s:%d\n", ipv6_buf, ntohs(peer_addr.sin6.sin_port));
        break;
    case AF_UNIX:
        printf("来自Unix域套接字:%s\n", peer_addr.sun.sun_path);
        break;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 17:35:25