项目代码笔记

1.bind函数的用法:

对一个函数绑定一个,或多个固定的参数

print(const std::string &str,......);

print("hello",.......);

或者

auto func =bind(print,"hello",......);

func();

此时,两者的结果一致,原理是bind函数可以依据一个函数的地址为其绑定n个固定的参数,并返回一个新的函数(这里取名为func()),当执行func()时就相当于执行print("hello",.....);

除此之外,我们还可以为func()手动添加参数(非固定参数):

void print(int a, int b, int c, int d, int e) {

std::cout << a << " " << b << " " << c << " " << d << " " << e << std::endl;

}

auto func = std::bind(print, 1, 2, 3, std::placeholders::_1, std::placeholders::_2);

func(4, 5); // 输出:1 2 3 4 5

这里的placeholders表示预留一个参数位,后面更一个::_1表示这是第一个参数,std::placeholders::_2则表示预留第二个手动输入的参数,

所以func(4,5)中的4和5就会去代替std::placeholders::_1和std::placeholders::_2

当然我们也可以直接这样写std::bind(print, 1, 2, 3, 4,5);

2.定时器(timerfd

1️⃣创建定时器

复制代码
#include <sys/timerfd.h>

int timerfd_create(int clockid, int flags);

clockid - 时钟类型

时钟类型 说明
CLOCK_REALTIME 系统实时时钟,受 NTP 调整影响,如果系统时间变化,就会影响到定时器
CLOCK_MONOTONIC 单调递增时钟,不受系统时间调整影响(推荐),记录系统启动时间
CLOCK_BOOTTIME 包含系统休眠时间的单调时钟
CLOCK_REALTIME_ALARM 需要 root 权限,可唤醒系统
CLOCK_BOOTTIME_ALARM 需要 root 权限,可唤醒系统

flags - 标志位

标志 说明
0 默认行为
TFD_NONBLOCK 设置为非阻塞模式
TFD_CLOEXEC 执行 exec 时自动关闭文件描述符

返回值

  • 成功:返回文件描述符

  • 失败:返回 -1,设置 errno

定时器超时时,内核会自动向 timerfd 文件描述符(tfd)写入一个 8 字节的数字,表示超时次数。

复制代码
int tfd = timerfd_create(CLOCK_MONOTONIC, 0);
// 设置定时器:每 1 秒超时一次
timerfd_settime(tfd, 0, &new_val, NULL);

// 关键:当超时发生时,内核自动向 tfd 写入 8 字节数据
uint64_t expirations;
read(tfd, &expirations, sizeof(uint64_t));  // 阻塞等待超时

用户程序                   内核
   │                       │
   ├─ timerfd_create() ───→│ 创建定时器对象
   │                       │
   ├─ timerfd_settime() ──→│ 启动定时器(1秒)
   │                       │
   │                       │ ⏰ 1秒后超时!
   │                       │ 自动向 tfd 写入: 0x0001
   │←───── read() 返回 ────┤ (写入8字节数据)
   │   expirations = 1     │
   │                       │
   │                       │ ⏰ 又过1秒,再次超时
   │                       │ 自动向 tfd 写入: 0x0002
   │←───── read() 返回 ────┤ (累计超时2次)
   │   expirations = 2     │

2️⃣启动或停止定时器

复制代码
#include <sys/timerfd.h>

int timerfd_settime(int fd, int flags, 
                    const struct itimerspec *new_value,
                    struct itimerspec *old_value);

参数详解

1. fd - 文件描述符

  • 来源 :由 timerfd_create() 创建的定时器文件描述符

  • 作用:指定要操作的定时器

    int tfd = timerfd_create(CLOCK_REALTIME, 0);
    timerfd_settime(tfd, ...);

2. flags - 标志位

决定 new_value 中的 it_value 如何解释:

标志 含义
0 相对时间(相对于当前时间)
TFD_TIMER_ABSTIME 绝对时间(从 Epoch 1970-01-01 开始)
TFD_TIMER_CANCEL_ON_SET 当系统时间被调整时取消定时器(需配合 ABSTIME)

示例:

复制代码
// 相对时间:3秒后超时
timerfd_settime(fd, 0, &new_val, NULL);

// 绝对时间:在 2025-01-01 00:00:00 超时
timerfd_settime(fd, TFD_TIMER_ABSTIME, &new_val, NULL);

3. new_value - 新定时器值(输入)

指向 struct itimerspec,设置定时器的超时时间和间隔。

复制代码
struct itimerspec {
    struct timespec it_interval;  // 周期性间隔(0=单次)
    struct timespec it_value;     // 首次超时时间
};

struct timespec {
    time_t tv_sec;   // 秒
    long   tv_nsec;  // 纳秒 (0-999999999)
};

配置示例:

复制代码
struct itimerspec new_val;

// 单次定时器:3秒后超时一次
new_val.it_value.tv_sec = 3;
new_val.it_value.tv_nsec = 0;
new_val.it_interval.tv_sec = 0;
new_val.it_interval.tv_nsec = 0;

// 周期性定时器:2秒后开始,每隔1秒超时一次
new_val.it_value.tv_sec = 2;      // 首次 2秒
new_val.it_value.tv_nsec = 0;
new_val.it_interval.tv_sec = 1;   // 之后每 1秒
new_val.it_interval.tv_nsec = 0;

// 停止定时器
new_val.it_value.tv_sec = 0;
new_val.it_value.tv_nsec = 0;

4. old_value - 旧定时器值(输出)

  • 作用:返回之前的定时器设置(可为 NULL)

  • 注意 :如果 old_value 非 NULL,函数会写入之前的配置

    struct itimerspec old_val;
    timerfd_settime(fd, 0, &new_val, &old_val);
    // old_val 现在保存修改前的定时器设置

返回值

返回值 含义
0 成功
-1 失败,设置 errno

3.正则表达式

对一个字符串,提取,匹配或替换里面的数据,就是正则表达式

复制代码
bool std::regex_match(
    const std::string& str,           // 目标字符串
    std::smatch& m,                   // 匹配结果(存储提取的数据)
    const std::regex& re              // 正则表达式对象
);

三种正则表达式:

函数 必需参数 可选参数 返回值
regex_match 字符串, 正则 匹配结果 bool
regex_search 字符串, 正则 匹配结果 bool
regex_replace 字符串, 正则, 替换串 标志 string

1️⃣std::smatch类型

std::smatch类型是类似于数组的容器,在正则表达式中,他不会保存整个原字符串,但会保存原字符串的匹配结果的索引信息

复制代码
原字符串 text:
┌─────────────────────────────────────────┐
│ H e l l o   w o r l d ,   w e l c o m e │
└─────────────────────────────────────────┘
  ↑           ↑
  0           6

matches 内部:
┌─────────────────────────────────────────┐
│ 指向原字符串的指针 ──────────┐           │
│ matches[0]: {pos:0, len:11}  │ (完整匹配 "Hello world")
│ matches[1]: {pos:0, len:5}   │ (第1组 "Hello")
│ matches[2]: {pos:6, len:5}   │ (第2组 "world")
└─────────────────────────────────────────┘

2️⃣re

re是正则表达式的匹配规则,是一个regex类型的变量,

复制代码
 std::regex re(R"(\$(\d+)\.(\d+))");

核心其实还是字符串的匹配

一、核心规则速查表

规则类型 符号 含义 示例 匹配
普通字符 字母数字 匹配自身 abc "abc"
通配符 . 匹配任意单个字符(除\r\n) a.c "abc", "aXc"
转义 \\ 把特殊字符变成普通字符 \\. \\ "." "?"
字符集 [...] 匹配其中任意一个字符 [aeiou] "a","e","i","o","u"
排除字符 [^...] 匹配除这些外的字符 [^0-9] 非数字
范围 - 字符范围 [a-z] 小写字母

需要双反斜杠查询?的原因,c++中有预定义字符,当你写出\?是,c++首先会想到\d,\D这样的预定义字符,但是没有\?所以会报错,当你\\后C++会认为是\(转义字符),此时\?就是字符?了

二、重复/量词规则

符号 含义 示例 匹配
* 0次或多次 a* "", "a", "aa"
+ 1次或多次 a+ "a", "aa"
? 0次或1次 a? "", "a"
{n} 恰好n次 a{3} "aaa"
{n,} 至少n次 a{2,} "aa", "aaa"
{n,m} n到m次 a{2,4} "aa","aaa","aaaa"

三、位置锚点规则

符号 含义 示例 匹配
^ 行的开头 ^Hello "Hello..."
$ 行的结尾 world$ "...world"
\b 单词边界 \bcat\b "cat" 单独出现
\B 非单词边界 \Bcat "scat" 中的 "cat"

四、预定义字符类

符号 含义 等价于 示例
\d 数字 [0-9] \d{11} 匹配11位数字
\D 非数字 [^0-9]
\w 单词字符 [a-zA-Z0-9_] \w+ 匹配单词
\W 非单词字符 [^a-zA-Z0-9_]
\s 空白字符 [ \t\n\r\f\v]
\S 非空白字符 [^ \t\n\r\f\v]

五、分组和捕获

符号 含义 示例
( ) 分组捕获(提取) (\d{4})-(\d{2}) 提取年月
(?: ) 非捕获分组 (?:abc) 只匹配不捕获
\1, \2 反向引用 (.)\1 匹配重复字符如"aa"
` `

4.日志宏

| 符号 | 含义 | 示例 |
| ... | 不定参(表示参数数量和内容不限定) | LOG(a,b,...) |
| VA_ARGS | 用来被不定参替换(或者接受不定参) | fprintf(VA_ARGS) |
| ## | 表示没有不定参的时候可以忽略__VA_ARGS__ | fprintf(##VA_ARGS) |

\ 宏要求内容必须始终处于同一行,\表示一个该行和下一行处于同一行(相当于英语中的换行继续写) do{\ }while()

5.setsockopt()

复制代码
setsockopt(_sockfd, SOL_SOCKET, SO_REUSEADDR, (void*)&val, sizeof(int));

这 5 个参数分别控制:操作哪个 socket哪一层协议哪个选项设置什么值值多长

参数逐个解释

参数 含义
_sockfd socket 文件描述符 要操作的 socket
SOL_SOCKET 套接字层 设置的是 socket 本身的选项(而非 TCP/UDP 层)
SO_REUSEADDR 地址重用选项 具体要设置哪个属性
(void*)&val 指向 val 的指针 设置val的值(1=开启,0=关闭),开启或关闭socket的选项
sizeof(int) 4 字节 告诉内核 val 有多大

第二个参数

复制代码
// 常用层级
SOL_SOCKET   // socket 层(通用选项)
IPPROTO_TCP  // TCP 层(TCP 专用选项)
IPPROTO_IP   // IP 层(IP 专用选项)

6.int fcntl();

复制代码
#include <unistd.h>
#include <fcntl.h>

int fcntl(int fd, int cmd, ... /* arg */);

参数说明

参数 含义
fd 要操作的文件描述符(socket、文件等)
cmd 要执行的命令(做什么操作)
... 可选参数,取决于 cmd

常用命令(cmd)

命令 作用 是否需要第3个参数
F_GETFL 获取文件状态标志 不需要
F_SETFL 设置文件状态标志 需要(新标志)
F_GETFD 获取文件描述符标志 不需要
F_SETFD 设置文件描述符标志 需要
F_DUPFD 复制文件描述符 需要

1. F_GETFL - 获取文件状态标志

复制代码
int flag = fcntl(fd, F_GETFL, 0);
// 返回当前的文件状态标志

常用标志位:

标志 含义
O_RDONLY 只读
O_WRONLY 只写
O_RDWR 读写
O_NONBLOCK 非阻塞模式
O_APPEND 追加模式
O_SYNC 同步写入

2. F_SETFL - 设置文件状态标志

复制代码
int ret = fcntl(fd, F_SETFL, new_flags);
// 设置新的文件状态标志

7.socket()