Linux入门DAY37(IO 多路复用、TCP 并发服务器与数据库 SQLite3 详解)

#Linux#IO多路复用#epoll#TCP并发服务器#SQLite3#网络编程

前言

在 Linux 网络开发中,单循环服务器一次只能服务一个客户端,无法应对多客户端同时接入的场景。为了实现并发服务器,我们有多进程、多线程、IO 多路复用三类方案。其中 IO 多路复用是高性能网络开发的核心技术,Nginx、Redis 等经典开源项目底层都基于 epoll 实现。

网络数据完成交互之后,往往需要做数据持久化,嵌入式领域最常用就是轻量级文件数据库 SQLite3。本文就从 IO 多路复用开始,梳理并发服务器模型以及 SQLite 数据库全套知识点。

一、IO 多路复用

IO 多路复用核心思想:单个进程 / 线程,同时监控多个文件描述符,当某个 fd 可读 / 可写事件触发,再去执行对应的 IO 操作,不需要创建大量进程线程,减少资源开销。

1.select

  1. 原理:使用位图数组维护需要监听的文件描述符集合,最大监听数量受内核默认1024限制。

  2. 缺点

    • 最大只能监控 1024 个文件描述符;
    • 用户态和内核态之间频繁拷贝 fd 集合;
    • 事件到来返回完整集合,应用程序需要循环遍历全部 fd 判断哪个就绪;
    • 仅支持水平触发。
  3. 核心 API

    int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
    //配套宏
    FD_ZERO(&fds); //清空集合
    FD_SET(fd, &fds); //添加fd到集合
    FD_CLR(fd, &fds); //从集合删除fd
    FD_ISSET(fd, &fds); //判断fd是否就绪

  • nfds:监控最大文件描述符 + 1;
  • readfds/writefds/exceptfds:读、写、异常事件集合;
  • timeout:超时时间,填 NULL 代表永久阻塞等待事件。
  • 返回值:就绪事件个数;0 代表超时;-1 代表出错。

2.poll

  1. 原理:使用链表保存待监听文件描述符集合,解除 1024 上限。
  2. 缺点
    • 仍然需要用户层和内核层来回拷贝数据;
    • 事件返回后,应用程序依旧需要遍历所有描述符找就绪 fd;
    • 只支持水平触发。

3.epoll(Linux 独有,高性能)

epoll 是 Linux 下 IO 多路复用最高效实现,Nginx、Redis 底层采用。

  1. 特点

    • 使用红黑树在内核维护 fd 集合,没有 1024 数量上限;
    • 内核直接返回已经就绪的事件,不需要全部遍历
    • 支持水平触发、边沿触发两种模式;
  2. 三套核心 API

    //1.创建epoll实例,返回epoll文件描述符
    int epoll_create(int size);

    //2.对监控集合做增删改操作
    int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
    //op: EPOLL_CTL_ADD 添加;EPOLL_CTL_MOD 修改;EPOLL_CTL_DEL 删除

    //3.阻塞等待事件到来
    int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

  • epoll_event结构体保存 fd 和关注事件(EPOLLIN 读事件、EPOLLOUT 写事件)。
  • 返回就绪事件的数量。

触发模式:

  • 水平触发 LT:只要缓冲区有数据就一直通知;select/poll 默认模式。
  • 边沿触发 ET:只有状态发生变化才通知一次,读写必须一次性读完缓冲区所有数据,性能更高。

二、TCP 并发服务器

单循环 TCP 服务器:同一时间只能处理一个客户端连接,客户端处理完成之后才能接待下一个。 并发服务器:同时服务多个客户端,有三种主流实现方式。

方式 1:多进程并发服务器

  1. 流程:socket→bind→listen,循环调用accept获取客户端连接,fork()创建子进程专门和该客户端通信;父进程继续等待新连接。
  2. 优缺点 ✅ 进程之间数据隔离,稳定性高; ❌ 进程资源开销大,大量客户端时系统压力高,需要处理僵尸进程回收。

方式 2:多线程并发服务器

  1. 流程:主线程循环accept得到客户端 connfd,调用pthread_create创建子线程处理客户端 IO;设置线程分离属性pthread_detach,线程结束操作系统自动回收资源。
  2. 优缺点 ✅ 线程开销远小于进程,创建速度快; ❌ 线程共享进程资源,一个线程崩溃会造成整个进程退出;多线程需要处理互斥锁同步。

方式 3:IO 多路复用并发服务器(epoll)

  1. 流程: 1)创建 socket、bind、listen; 2)创建 epoll,把监听套接字sockfd加入 epoll 监听集合; 3)循环执行epoll_wait等待事件; 4)如果是监听套接字就绪,调用 accept 获取新客户端 fd,加入 epoll; 5)如果是客户端 connfd 就绪,执行 recv/send 完成数据收发。
  2. 优缺点 ✅ 单进程即可实现高并发,资源消耗极低;工业高性能服务器主流; ❌ 编码逻辑相对复杂,只支持 Linux 平台。

UDP 本身天然并发,不需要上述模型。

三、数据库 --- SQLite3

3.1 数据库基础概念

  1. 普通文件:直接读写文件,增删改查逻辑全部由程序员自己实现,大数据量效率低下。
  2. 数据库:专门用于数据管理,高效完成增删改查。
    • 关系型数据库:Oracle、MySQL、SQLite(二维表格)
    • 非关系型数据库:Redis、MongoDB(键值存储)
  3. SQLite3 特点(嵌入式首选)
  • 开源免费纯 C 实现;
  • 文件型数据库,整个数据库保存在一个.db文件,可以直接拷贝迁移;
  • 资源占用很小,最大支持 2TB 数据。

3.2 Linux 环境安装

复制代码
sudo apt install sqlite3
sudo apt install libsqlite3-dev
#可视化工具
sudo apt install sqlitebrowser

3.3 sqlite3 命令行常用指令

复制代码
#打开数据库文件
sqlite3 test.db
.tables              #查看全部表
.headers on          #打开表头
.mode column         #对齐输出
.quit                #退出

SQL 语句(大小写不敏感)

  1. 创建表

    CREATE TABLE class1(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, score REAL);

  2. 插入数据

    insert into class1(name,score) values("zhangsan",88);

  3. 查询

    select * from class1;
    select * from class1 where score>60 order by score desc;

  4. 修改

    update class1 set score=90 where name="zhangsan";

  5. 删除

    delete from class1 where id=2;
    drop table class1;

数据类型:INTEGER整型、REAL浮点、TEXT字符串、BLOB二进制。

3.4 SQLite3 C 语言 API

  1. sqlite3_open():打开数据库文件,获取数据库句柄
  2. sqlite3_errmsg():获取错误提示字符串
  3. sqlite3_exec():执行 SQL 语句。
    • 参数包含回调函数:执行 select 查询的时候,每读到一行数据就调用一次回调函数
    • 回调函数参数:列数量、每列值、表头名称;回调必须返回 0。
  4. 预处理接口 sqlite3_prepare_v2 / sqlite3_bind_text / sqlite3_step / sqlite3_finalize:适合带变量插入查询,防止 SQL 注入,词典项目就是使用这套 API。
  5. sqlite3_close():关闭数据库句柄。

编译要点:gcc 编译时必须链接库 -lsqlite3

小结

  1. IO 多路复用解决单进程处理多路 IO 的问题,select受限于 1024,poll解除数量上限,epoll是 Linux 高性能首选,支持水平触发、边沿触发。
  2. TCP 并发服务器实现方案对比:
    • 多进程:稳定性高,资源开销大;
    • 多线程:开销中等,共享内存有线程安全风险;
    • epoll IO 多路复用:单进程高并发,Nginx/Redis 采用。
  3. SQLite3 是嵌入式轻量文件数据库,掌握命令行 SQL 语句和 C 语言两套 API,可实现数据持久化存储;编译链接‑lsqlite3
  4. 工程中词典导入数据库作业,就是使用sqlite3_prepare_v2预处理接口读取文本文件批量插入,再接收终端输入做数据库查询。
相关推荐
新时代牛马1 小时前
Linux 块设备驱动完整篇:从gendisk、submit_bio 到blk-mq queue_rq 与排障
linux·运维·服务器
不吃鱼的羊1 小时前
Davinci Developer的IRV
服务器
2501_930472441 小时前
05_数据库迁移腾讯云_DTS评估与预检回滚清单
数据库·云计算·腾讯云
德迅云安全杨德俊1 小时前
裸金属服务器的运用与适用场景
运维·服务器
三8441 小时前
SSRF 从入门到实战(下篇):gopher 打 Redis 实现 RCE
数据库·redis·缓存
chinesegf2 小时前
现代互联网服务的经典架构
服务器·架构·llama
Rsingstarzengjx2 小时前
第二十六章 Linux 蜂鸣器实验笔记
linux·驱动开发·笔记·stm32·嵌入式硬件·stm32mp157
承渊政道2 小时前
从GB到TB:KFS如何实现高吞吐、有序的异构增量同步
数据库·kingbase·延迟优化·kfs·数据量级优化
Java小学生丶2 小时前
[开源自荐] ZTShell,一个使用 Tauri 2 + Rust 全程由 AI 开发的跨平台桌面 SSH 工具
linux·网络·centos7·云服务器·开发技巧·资源分享·个人私货