刷题:

|---|---------------------------------------------|
| | # 超时检测核心要点 |
| | |
| | ## 1. 基本类型 |
| | ### 阻塞模式 |
| | - 永久等待数据,无超时机制 |
| | - 典型函数:`recv()`阻塞调用 |
| | |
| | ### 非阻塞模式 |
| | - 立即返回结果(成功/错误) |
| | - 设置方式:`fcntl(fd, F_SETFL, O_NONBLOCK)``` | | | | | | `### 超时检测` | | | `- 设置等待阈值,超时返回错误` | | | `- 应用场景:网络请求、心跳包` | | | | | | `---` | | | | | | `## 2. 超时检测函数` | | | `### select函数` | | | - 参数:struct timeval设置秒和微秒`` |
| | - 示例: |
| | ```````c```` |
| | struct timeval tm = {3, 0}; |
| | if (select(..., &tm) == 0) { /* 超时处理 */ } |
poll函数
-
参数:超时时间(毫秒)
-
示例:
if (poll(fds, 10, 3000) == 0) { /* 超时处理 */ }
epoll_wait
-
参数:超时时间(毫秒)
-
示例:
if (epoll_wait(epfd, events, 10, 3000) == 0) { /* 超时处理 */ }
setsockopt
-
设置收发超时:
|---|---------------------------------------------------------------------------|
| |struct timeval rcv_timeo = {3, 0};|
| |setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &rcv_timeo, sizeof(rcv_timeo));|
3. 心跳包机制
核心作用
- 维持长连接活跃状态
- 检测客户端存活(TCP/UDP均适用)
实现步骤
- 客户端:周期发送空包(如每5秒)
- 服务端 :
- 维护客户端列表(IP+Port+最后通信时间)
- 定时任务检测超时(如60秒无响应判定离线)
数据结构
-
消息类型 :
enum type_t { CHAR, HEART }; // 区分业务包和心跳包 -
时间记录 :
|---|----------------------------|
| |typedef struct timebuf {|
| |unsigned int ip;|
| |unsigned short port;|
| |time_t tm; // 最后通信时间戳|
| |} timebuf_t;|
4. 信号处理
alarm函数
-
周期性触发信号(如每5秒)
-
示例:
|---|-----------------------------|
| |signal(SIGALRM, handler);|
| |alarm(5);|
sigaction配置
-
关闭自重启属性 :
|---|--------------------------------------------|
| |struct sigaction act;|
| |sigaction(SIGALRM, NULL, &act); // 获取原属性|
| |act.sa_flags &= ~SA_RESTART; // 关闭自重启|
| |sigaction(SIGALRM, &act, NULL); // 设置新属性| -
超时中断处理 :
|---|------------------------------------|
| |void handler(int sig) {|
| |printf("超时中断!");|
| |// 中断阻塞操作(如recv返回-1,errno=EINTR)|
| |}|
5. 代码实现示例
TCP服务端超时检测
- 关键步骤:
- 创建socket并绑定监听
- 使用
alarm设置超时信号 - 在
recv中捕获超时错误(errno == EINTR)
UDP心跳包服务端
-
核心逻辑:
|---|------------------------------------------------|
| |while (1) {|
| |ret = recvfrom(sockfd, &buf, ..., &cliaddr);|
| |if (ret > 0) {|
| |update_time(cliaddr); // 更新时间戳|
| |if (buf.type == HEART) continue; // 心跳包不处理业务|
| |}|
| |}|
|---|-----------------------------------|
| | # UNIX域套接字核心要点 |
| | |
| | ## 1. 基本概念 |
| | ### 本地通信机制 |
| | - 通过文件路径而非网络地址通信 |
| | - 适用场景:高效本地进程间通信 |
| | - 文件类型:`s`类型套接字文件 |
| | |
| | ### 与网络套接字对比 |
| | - **网络通信**:自动填充客户端IP+Port |
| | - **域套接字**:需手动绑定路径实现双向通信 |
| | |
| | --- |
| | |
| | ## 2. TCP域套接字 |
| | ### 服务端流程 |
| | 1. **创建套接字**: |
| | ```````c```` |
| | socket(AF_UNIX, SOCK_STREAM, 0) |
-
绑定路径 :
|---|-----------------------------------------------------|
| |struct sockaddr_un addr = {.sun_family=AF_UNIX};|
| |strcpy(addr.sun_path, "./unix_socket");|
| |bind(sfd, (struct sockaddr*)&addr, sizeof(addr));| -
监听连接 :
listen(sfd, 5); -
接受连接 :
accept(sfd, NULL, NULL); // 忽略客户端路径
客户端流程
-
创建套接字:同服务端
-
连接服务端 :
connect(cfd, (struct sockaddr*)&server_addr, sizeof(server_addr));
关键函数
access():检查文件存在性unlink():删除旧套接字文件避免绑定失败
3. UDP域套接字
服务端实现
-
绑定路径 :必须显式绑定
bind(sfd, "./server_socket"); -
接收消息 :
recvfrom(sfd, buf, sizeof(buf), 0, (struct sockaddr*)&cliaddr, &len); -
发送响应 :需客户端路径
sendto(sfd, buf, strlen(buf), 0, (struct sockaddr*)&cliaddr, len);
客户端实现
-
必须绑定路径 :否则服务端无法回复
bind(cfd, "./client_socket"); -
发送消息 :
sendto(cfd, buf, strlen(buf), 0, (struct sockaddr*)&server_addr, len);
4. 并发与优化
epoll模型应用
-
非阻塞设置 :
fcntl(fd, F_SETFL, O_NONBLOCK); -
事件监听 :
epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event); -
边缘触发 :
event.events = EPOLLIN | EPOLLET;
文件管理
-
路径冲突处理 :
if (access("./socket_file", F_OK) == 0) unlink("./socket_file");
5. 数据结构
地址结构体
|---|--------------------------------------|
| | struct sockaddr_un { |
| | sa_family_t sun_family; // AF_UNIX |
| | char sun_path[108]; // 套接字文件路径 |
| | }; |
消息格式
|---|----------------------------------------|
| | typedef struct { |
| | enum { CHAR, HEART } type; // 数据类型标识 |
| | char text[128]; // 实际数据 |
| | } msgbuf_t; |

|---|-----------------------------------|
| | # TCP粘包问题核心要点 |
| | |
| | ## 基本概念 |
| | ### 粘包现象定义 |
| | - 数据包在传输过程中发生粘连 |
| | - 表现为接收端无法区分原始数据边界 |
| | |
| | ### 发生场景 |
| | - TCP流式传输固有特性 |
| | - 发送/接收缓冲区大小不一致 |
| | - 网络传输延迟导致数据堆积 |
| | |
| | ## 核心成因 |
| | ### 协议特性 |
| | - TCP面向字节流的传输方式 |
| | - UDP数据报传输天然无粘包 |
| | |
| | ### 应用层因素 |
| | - 发送端数据写入过快 |
| | - 接收端读取不及时 |
| | - 数据包大小与缓冲区不匹配 |
| | |
| | ## 解决方案设计 |
| | ### 数据封包协议 |
| | - 固定包头结构: |
| | ```````c```` |
| | typedef struct { |
| | uint32_t length; // 数据长度(网络字节序) |
| | char data[]; // 实际数据 |
| | } tcp_packet_t; |
- 包头校验机制(CRC32/MD5)
发送端实现
- 数据分片预处理
- 添加4字节长度头
- 使用htonl转换字节序
- 分次发送保证完整性
接收端实现
- 先读取4字节包头
- ntohl转换获得数据长度
- 循环读取直到数据完整
- 缓冲区动态扩容机制
代码实现关键点
服务器端核心逻辑
- 双重接收循环结构
- 非阻塞读取超时处理
- 数据完整性校验
- 异常断开检测机制
客户端核心逻辑
- 文件分块随机读取
- 内存预分配策略
- 数据分片发送保障
- 错误重传机制
性能优化方向
传输层优化
- 设置TCP_NODELAY选项
- 调整SO_SNDBUF/SO_RCVBUF
应用层优化
- 滑动窗口协议实现
- 双缓冲区分包处理
- 异步IO事件驱动模型
错误处理机制
常见异常场景
- 数据包长度校验失败
- 接收缓冲区溢出
- 网络传输中断
- 字节序转换错误
健壮性设计
- 心跳包维持连接
- 数据包重传请求
- 校验和验证机制
- 连接异常中断恢复