sockaddr_in
是用于表示 IPv4 地址和端口的结构体,常用于网络编程中的套接字(socket)通信。它是 sockaddr
的专用形式,专门针对 IPv4 地址设计。
概念解析
struct sockaddr_in
定义在头文件 <netinet/in.h>
中,结构如下:
struct sockaddr_in {
sa_family_t sin_family; // 地址族(AF_INET 表示 IPv4)
in_port_t sin_port; // 端口号(16位,需用网络字节序)
struct in_addr sin_addr; // IPv4 地址(32位,网络字节序)
char sin_zero[8]; // 填充字段(未使用,通常置0)
};
struct in_addr {
uint32_t s_addr; // IPv4 地址(网络字节序)
};
sin_family
:固定为AF_INET
(IPv4)。sin_port
:端口号,需用htons()
转换为主机到网络的字节序。sin_addr
:IPv4 地址,可用INADDR_ANY
表示绑定到本机所有 IP。sin_zero
:填充字段,确保sockaddr_in
和sockaddr
大小一致。
使用案例
示例1:TCP 服务器绑定地址
以下是一个简单的 TCP 服务器代码,使用 sockaddr_in
绑定地址并监听连接:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
// 1. 创建套接字
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// 2. 设置套接字选项(可选:允许地址重用)
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
// 3. 配置 sockaddr_in 结构
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY; // 绑定到所有本地接口
address.sin_port = htons(8080); // 绑定到端口 8080
// 4. 绑定套接字到地址
if (bind(server_fd, (struct sockaddr*)&address, sizeof(address)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
// 5. 监听连接
if (listen(server_fd, 3) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
printf("Server listening on port 8080...\n");
// 6. 接受客户端连接
if ((new_socket = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen)) < 0) {
perror("accept");
exit(EXIT_FAILURE);
}
printf("Client connected from %s:%d\n",
inet_ntoa(address.sin_addr), ntohs(address.sin_port));
// ...后续处理(发送/接收数据)
close(new_socket);
close(server_fd);
return 0;
}
示例2:客户端连接服务器
客户端使用 sockaddr_in
指定服务器地址:
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main() {
int sock = 0;
struct sockaddr_in serv_addr;
// 1. 创建套接字
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
// 2. 配置目标服务器地址
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(8080); // 目标端口
// 将字符串 IP 转换为网络字节序
if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
perror("invalid address");
exit(EXIT_FAILURE);
}
// 3. 连接到服务器
if (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
perror("connection failed");
exit(EXIT_FAILURE);
}
printf("Connected to server!\n");
// ...后续处理(发送/接收数据)
close(sock);
return 0;
}
关键点
-
字节序转换:
htons()
:将主机字节序的端口号转为网络字节序。inet_addr("127.0.0.1")
或inet_pton()
:将字符串 IP 转为网络字节序。
-
类型转换:
- 在调用
bind()
,connect()
,accept()
等函数时,需将sockaddr_in*
强制转换为sockaddr*
。
- 在调用
-
通用性:
sockaddr_in
用于 IPv4,IPv6 使用sockaddr_in6
,通用地址结构为sockaddr_storage
。
通过 sockaddr_in
,开发者可以方便地管理 IPv4 地址和端口,实现网络通信的基础操作。