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

listen() 函数详解

在这里插入图片描述

listen() 函数详解

listen() 是 TCP 服务器编程中的核心函数,用于将套接字置于被动监听状态,准备接受客户端连接请求。它在 bind() 之后、accept() 之前调用。

函数原型

#include <sys/socket.h>int listen(int sockfd, int backlog);

参数说明:

  • sockfd
    已绑定的套接字文件描述符(通过 socket() 创建并已调用 bind()
  • backlog
    等待连接队列的最大长度(内核为该套接字排队的最大连接数)

返回值:

  • 成功:返回 0
  • 失败:返回 -1 并设置 errno

工作原理图解

客户端连接请求           内核维护的队列│▼
┌───────────────┐       ┌──────────────────┐
│   SYN_RCVD    │◀──────│  未完成队列       │◀── 新连接请求(SYN)
│ (半连接状态)   │       │ (SYN_RCVD状态)    │     backlog 限制
└───────────────┘       └──────────────────┘│                        ││ 完成三次握手            │▼                        ▼
┌───────────────┐       ┌──────────────────┐
│  ESTABLISHED  │◀──────│   已完成队列      │◀── `accept()` 取走的连接
│ (全连接状态)   │       │ (ESTABLISHED状态)│
└───────────────┘       └──────────────────┘
  1. 未完成队列 (SYN队列)

    • 存储收到 SYN 但未完成三次握手的连接
    • 大小由系统参数决定(非 backlog 控制)
  2. 已完成队列 (Accept队列)

    • 存储已完成三次握手的连接
    • 最大长度 = min(backlog, net.core.somaxconn)

使用案例:TCP 服务器

#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>#define PORT 8080
#define BACKLOG 5  // 等待队列长度int main() {// 1. 创建套接字int server_fd = socket(AF_INET, SOCK_STREAM, 0);if (server_fd < 0) {perror("socket failed");return 1;}// 2. 绑定地址struct sockaddr_in address;memset(&address, 0, sizeof(address));address.sin_family = AF_INET;address.sin_addr.s_addr = INADDR_ANY;address.sin_port = htons(PORT);if (bind(server_fd, (struct sockaddr*)&address, sizeof(address)) < 0) {perror("bind failed");close(server_fd);return 1;}// 3. 开始监听if (listen(server_fd, BACKLOG) < 0) {perror("listen failed");close(server_fd);return 1;}printf("Server listening on port %d\n", PORT);// 4. 接受连接int addrlen = sizeof(address);while(1) {int new_socket = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen);if (new_socket < 0) {perror("accept failed");continue;}printf("New connection accepted\n");// 处理客户端请求...char *response = "HTTP/1.1 200 OK\nContent-Type: text/plain\n\nHello from server!";send(new_socket, response, strlen(response), 0);close(new_socket); // 关闭客户端套接字}close(server_fd);return 0;
}

关键注意事项

1. backlog 参数的最佳实践

  • 现代系统:实际队列长度 = min(backlog, net.core.somaxconn)
  • 查看系统限制:
    cat /proc/sys/net/core/somaxconn  # 通常默认128
    
  • 推荐值
    • 轻负载:5-10
    • 高并发:1000+(需同步调整系统参数)
    • 生产环境:根据压力测试调整

2. 错误处理

常见错误码:

  • EADDRINUSE:端口已被占用(检查是否重用套接字)
  • EBADF:无效套接字描述符
  • ENOTSOCK:文件描述符不是套接字
  • EOPNOTSUPP:套接字类型不支持监听

3. 完整连接建立流程

ClientServerKernelsocket()bind()listen(fd, backlog)创建SYN队列和Accept队列SYN (连接请求)不通知应用层accept() 阻塞等待SYN+ACKACK (完成握手)accept() 返回新套接字ClientServerKernel

高级主题

1. SYN Flood 攻击防护

当未完成队列溢出时:

// 检查半连接状态
cat /proc/net/stat/syn_recv

防护措施

  • 启用内核参数 net.ipv4.tcp_syncookies = 1
  • 减少 net.ipv4.tcp_synack_retries(默认5)

2. 非阻塞模式下的 listen()

使用 fcntl() 设置非阻塞:

fcntl(server_fd, F_SETFL, O_NONBLOCK);

此时 accept() 立即返回:

  • 有连接:返回有效描述符
  • 无连接:返回 -1 且 errno = EAGAIN/EWOULDBLOCK

3. 多线程/多进程模型

while(1) {int client_fd = accept(...);if (fork() == 0) {  // 子进程处理close(server_fd); handle_client(client_fd);exit(0);}close(client_fd);  // 父进程关闭客户端fd
}

常见问题解答

Q:backlog 设置为 0 会怎样?
A:行为取决于系统,Linux 中会允许至少1个连接(实际值 = max(backlog, 1)

Q:客户端在 accept() 前完成连接会怎样?
A:连接存入完成队列,等待 accept() 取出,不会丢失

Q:如何监控队列状态?

# 查看Accept队列溢出
netstat -s | grep "listen queue"# 查看SYN队列溢出
netstat -s | grep "SYNs to LISTEN"

Q:为什么需要 listen() 而 UDP 不需要?
A:TCP 是面向连接的协议,需要维护连接状态;UDP 是无连接的。

💡 最佳实践listen() 是TCP服务器启动的最后一步准备,合理的 backlog 设置对高并发系统至关重要,需结合系统参数优化。加粗样式

http://www.lryc.cn/news/601233.html

相关文章:

  • GPGPU基本概念
  • 深入解析 Vue 3 中 v-model 与表单元素的绑定机制
  • 北京-4年功能测试2年空窗-报培训班学测开-第六十一天-模拟面试第一次
  • 五自由度磁悬浮轴承转子不平衡振动破壁战:全息前馈控制实战密码
  • 结构化文本文档的内容抽取与版本重构策略
  • 程序代码篇---python获取http界面上按钮或者数据输入
  • LeetCode 611.有效三角形的个数
  • 机器学习项目一基于KNN算法的手写数字识别
  • 设计模式(十二)结构型:享元模式详解
  • AI Coding IDE 介绍:Cursor 的入门指南
  • 设计模式(八)结构型:桥接模式详解
  • 以太坊ETF流入量超越比特币 XBIT分析买币市场动态与最新价格
  • 分类预测 | MATLAB基于四种先进的优化策略改进蜣螂优化算法(IDBO)的SVM多分类预测
  • 机器学习—线性回归
  • 数学基础薄弱者的大数据技术学习路径指南
  • Java Ai (day01)
  • Oracle EBS 库存期间关闭状态“已关闭未汇总”处理
  • 【网络协议安全】任务15:DHCP与FTP服务全配置
  • docker与k8s的容器数据卷
  • S7-1500 与 S7-1200 存储区域保持性设置特点详解
  • 三、搭建springCloudAlibaba2021.1版本分布式微服务-springcloud loadbalancer负载均衡
  • Java 大视界 -- Java 大数据机器学习模型在电商客户细分与精准营销活动策划中的应用(367)
  • 机械学习----knn实战案例----手写数字图像识别
  • 人工智能开发框架 04.网络构建
  • spring gateway 配置http和websocket路由转发规则
  • Linux驱动21 --- FFMPEG 音频 API
  • Spring Boot + @RefreshScope:动态刷新配置的终极指南
  • mysql 快速上手
  • 发布 VS Code 扩展的流程:以颜色主题为例
  • 详解力扣高频SQL50题之1164. 指定日期的产品价格【中等】