Bootstrap

sockaddr_in的概念和使用案例

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_insockaddr 大小一致。

使用案例

示例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;
}

关键点

  1. 字节序转换

    • htons():将主机字节序的端口号转为网络字节序。
    • inet_addr("127.0.0.1")inet_pton():将字符串 IP 转为网络字节序。
  2. 类型转换

    • 在调用 bind(), connect(), accept() 等函数时,需将 sockaddr_in* 强制转换为 sockaddr*
  3. 通用性

    • sockaddr_in 用于 IPv4,IPv6 使用 sockaddr_in6,通用地址结构为 sockaddr_storage

通过 sockaddr_in,开发者可以方便地管理 IPv4 地址和端口,实现网络通信的基础操作。

;