sockaddr地址结构——socket

本文详细介绍了sockaddr结构体在早期网络编程中的作用,以及如何与后来出现的sockaddr_in结构体进行交互。通过示例展示了在IPV4环境下设置socket地址的过程,包括bind函数的使用,以及如何处理网络字节顺序。文章还提及了IPV4地址的局限性,以及为何需要过渡到IPV6的背景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

sockaddr地址结构

bind(sock, (struct sockaddr *)&server_addr, sizeof(server_addr));
// 像bind这些函数API在很早的时候就有了
// 而struct sockaddr_in 是后面出现的, 针对IPV4
// IPv4即4个字节(32位)来表示IP,那么也就4亿多IP
// 所以后面出现了IPv6, 用128个位来表示IP地址

一、sockaddr数据结构

struct sockaddr: 很多网络编程函数诞生早于IPV4,那时候都使用的是sockaddr结构体,为了向前兼容,现在sockaddr退化成了
    (void*)的作用,传递一个地址给函数,至于这个函数是sockaddr_in或其他,则是由地址族确定的,然后函数内部再强制类型转
    换为所需的地址类型。

请添加图片描述

1. struct sockaddr与struct sockaddr_in

struct sockaddr {
    sa_family_t  sa_family; //选择地址家族,AF_xxx | 例如是IPV4的就是选择AF_INET | AF_INET6
    char         sa_data[14]; // 地址数据
}

struct sockaddr_in {
    sa_family_t      sin_family; // 地址家族: AF_INET
    in_port_t        sin_port;   // 两字节的端口号(网络字节顺序)
    struct in_addr   sin_addr;   // 因特网地址
}

// 因特网地址
struct in_addr {
    uint32_t         s_addr;     //32位的网络字节顺序的IP地址(32位的无符号整型数)
    // 而且这个整型数要转换成字符串
    // 再如,若客户端要去连接某个IP地址,要将字符串转换成整型数
}

struct sockaddr_in server_addr;

server_addr.sin_family = AF_INET; // 选择协议家族IPV4
// INADDR_ANY 宏定义 代表本地所有IP地址 0.0.0.0 整型数
server_addr.sin_addr.s_addr = htonl(INADDR_ANY); //因为这是网络字节顺序的IP地址,所以要用htonl转换一下

server_addr.sin_port = htons(SERVER_PORT); // 网络字节顺序

// 在调用bind的时候,因为bind要求传递的参数是struct sockaddr 结构体,所以要做强制转换
// 实际上struct sockaddr和struct sockaddr_in结构相似,都是16个字节
/* 在这里指定的是IPv4 ,所以bind会在绑定的时候根据地址家族AF_INET(IPV4的),会自动的把传递的&server_addr再强制转换
	成sockaddr_in,所以不会有问题,即使二者结构不一样(在内部还是用的sockaddr_in处理)
 */
bind(sock, (struct sockaddr *)&server_addr, sizeof(server_addr));
### socket编程中的文件结构详解 在Linux环境下,`socket`被视作一种特殊的文件描述符。创建一个新的套接字实际上就是通过调用特定API函数获得一个用于表示网络连接的整数型句柄[^1]。 #### sockaddr结构解析 对于`sockaddr`结构而言,在实际应用中通常不会直接使用它,而是会采用其派生出来的更具体形式如`sockaddr_in`(IPv4)或`sockaddr_in6`(IPv6),因为这些扩展版本能够携带更多有关通信双方的信息。以下是针对IPv4协议族定义的一个常用结构体: ```c struct sockaddr_in { short sin_family; /* 地址簇, AF_INET */ unsigned short sin_port; /* 端口号 */ struct in_addr sin_addr; /* IP地址 */ char sin_zero[8]; /* 填充0至16字节边界 */ }; ``` 其中`sin_family`字段用来指定使用的地址家族;而`in_addr`则是一个包含IPV4地址信息的数据类型,一般情况下可以通过宏定义将其转换成字符串形式以便于显示和调试[^2]。 #### 创建Socket并绑定本地地址 当程序需要发起主动连接或者监听来自其他主机的消息时,则要先建立好自己的身份标识——即设置好本机在网络上的位置(IP+Port)。这一步骤涉及到两个重要操作:“创建”与“绑定”。 - **创建**:利用`socket()`系统调用生成新的未命名套接口对象,并获取对应的文件描述符作为后续读写的基础; - **绑定**:借助`bind()`方法将上述得到的匿名资源同具体的机器物理特性关联起来,使得外界可通过一定规则找到对应的服务进程。 ```c int sockfd; struct sockaddr_in serv_addr; /* Create a TCP Socket */ if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){ perror("ERROR opening socket"); exit(1); } memset(&serv_addr, '0', sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); // Bind to any address available on this machine. serv_addr.sin_port = htons(PORT); // Binding the server's port number and IP address with its socket descriptor if (bind(sockfd, (struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0){ perror("ERROR on binding"); close(sockfd); exit(1); } ``` 这段代码展示了如何初始化服务端所需的各项配置参数,并完成基本准备工作。值得注意的是这里采用了通配符INADDR_ANY让操作系统自动选取合适的网卡设备参与数据交换过程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

郑师傅炒板栗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值