当前位置: 首页 > article >正文

【linux网络编程】文件描述符

1. 什么是文件描述符?

文件描述符(FD) 是操作系统用来管理打开的文件或 I/O 资源(如套接字、管道、设备文件等)的整数索引

📌 在 Linux 中,一切皆文件

文件类型文件描述符
普通文件(文本、二进制)open("file.txt") 返回 FD
标准输入 (stdin)FD = 0
标准输出 (stdout)FD = 1
标准错误 (stderr)FD = 2
套接字(Socket)socket() 返回 FD

2. 套接字是文件描述符

当你使用 socket() 创建一个监听套接字时,操作系统会返回一个文件描述符,用于标识这个套接字。

📌 监听套接字创建示例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 8080

int main() {
    int server_fd;  // 监听套接字的文件描述符
    struct sockaddr_in server_addr;

    // 1. 创建 TCP 套接字(返回文件描述符)
    server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd == -1) {
        perror("Socket creation failed");
        exit(EXIT_FAILURE);
    }
    printf("Socket created with file descriptor: %d\n", server_fd);

    // 2. 绑定 IP 和端口
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(PORT);
    bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr));

    // 3. 监听端口
    listen(server_fd, 5);
    printf("Listening on port %d...\n", PORT);

    // 4. 关闭套接字
    close(server_fd);
    return 0;
}

📌 输出示例

Socket created with file descriptor: 3
Listening on port 8080...
  • socket() 返回的 server_fd = 3,表示监听套接字的文件描述符
  • 这个 server_fd 可以像普通文件一样 read()write()

3. 监听套接字 vs. 客户端套接字

在服务器程序中:

  1. socket() 创建监听套接字,返回 FD(如 server_fd=3)。
  2. accept() 接受客户端连接,返回新的 FD(如 client_fd=4)。
  3. client_fd 用于与客户端通信,而 server_fd 继续监听新的连接

📌 服务器 accept() 连接示例

int client_fd;
struct sockaddr_in client_addr;
socklen_t addr_len = sizeof(client_addr);

// 等待客户端连接
client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &addr_len);
printf("Accepted connection, new socket fd: %d\n", client_fd);

📌 示例输出

Socket created with file descriptor: 3
Listening on port 8080...
Accepted connection, new socket fd: 4
  • server_fd=3(监听套接字) 继续等待新连接。
  • client_fd=4(客户端套接字) 用于和客户端通信。

4. 使用 select() 监听多个文件描述符

Linux 提供 select() 允许同时监听多个文件描述符(包括套接字、标准输入、文件等)。

📌 监听 server_fdstdin

fd_set read_fds;
FD_ZERO(&read_fds);
FD_SET(server_fd, &read_fds);
FD_SET(STDIN_FILENO, &read_fds);  // 监听键盘输入

int max_fd = (server_fd > STDIN_FILENO) ? server_fd : STDIN_FILENO;
select(max_fd + 1, &read_fds, NULL, NULL, NULL);

if (FD_ISSET(server_fd, &read_fds)) {
    client_fd = accept(server_fd, NULL, NULL);
    printf("New client connected: %d\n", client_fd);
}

if (FD_ISSET(STDIN_FILENO, &read_fds)) {
    char buffer[1024];
    read(STDIN_FILENO, buffer, sizeof(buffer));
    printf("You typed: %s\n", buffer);
}

📌 总结

  • server_fd 监听网络连接
  • STDIN_FILENO 监听键盘输入
  • select() 允许多个文件描述符同时监听

5. 文件描述符的生命周期

  1. 创建

    • socket() 返回文件描述符,如 server_fd=3
    • accept() 返回新的连接文件描述符,如 client_fd=4
  2. 使用

    • read() / write()send() / recv() 进行通信。
    • 服务器使用 select()poll() 监听多个套接字。
  3. 关闭

    • close(server_fd) 释放监听套接字。
    • close(client_fd) 释放客户端套接字。

注意

  • 服务器不能关闭 server_fd,否则无法接受新连接
  • 客户端断开连接时,服务器应关闭 client_fd,避免文件描述符泄露。

6. 如何查看打开的文件描述符

Linux 提供 lsofnetstat 命令查看进程的打开套接字

lsof -i :8080   # 查看监听 8080 端口的进程
netstat -anp | grep 8080   # 查看 8080 端口连接状态

示例输出:

COMMAND    PID    FD   TYPE DEVICE SIZE/OFF NODE NAME
server    1234    3u  IPv4  12345      0t0  TCP *:8080 (LISTEN)
server    1234    4u  IPv4  12346      0t0  TCP 192.168.1.10:8080->192.168.1.20:50000 (ESTABLISHED)
  • server 1234 3u:进程 server 监听 8080 端口,文件描述符 3
  • server 1234 4u:建立了 TCP 连接,文件描述符 4

7. 总结

监听套接字(server_fd)是文件描述符(FD),它在 Linux 中就像一个文件一样被管理。
socket() 创建的监听套接字有一个 FD,accept() 返回的客户端连接也有自己的 FD。
服务器必须管理多个文件描述符(监听、客户端连接、标准输入等),可以使用 select() 监听多个 FD。
关闭 client_fd 释放客户端连接,但服务器 server_fd 必须保持打开以接受新连接。
lsof -inetstat 命令可查看监听端口和文件描述符信息。

📌 如果你在做 Linux 网络编程,理解“套接字 = 文件描述符” 是最核心的概念之一! 🚀


http://www.kler.cn/a/577126.html

相关文章:

  • C++题解(32) 2025顺德一中少科院信息学创新班(四期)考核复盘 U536935 黑白图像
  • JavaScript基础-比较运算符
  • springcloud sentinel教程
  • 电脑睡眠智能管控:定时、依状态灵活调整,多模式随心选
  • CameraX学习2-关于录像、慢动作录像
  • Python评估网络脆弱性
  • 对数几率回归(LogisticRegression)基础知识(包含分类任务的概念及评价指标)
  • Docker编排工具Docker Compose
  • sqlserver删除表记录语句,及删除表时清零ID的SQL语句
  • 【高级篇】大疆Pocket 3加ENC编码器实现无线RTMP转HDMI进导播台
  • CATIA V5 二次开发实战:Python实现零件实体智能转产品装配
  • 图像处理篇---opencv中的图像特征
  • C++程序设计语言笔记——基本功能:表达式
  • pytorch tensor创建tensor
  • Maven快速入门指南
  • 2025天津申论(综合市区) 第一题“反向旅游”
  • python:pymunk + pygame 模拟六边形内小球弹跳运动
  • Node.js中HTTPS模块应用详解
  • [补]数电笔记——逻辑代数基础
  • HarmonyOS 应用程序包结构 (发布态)