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

C++11实现TCP网络通讯服务端处理逻辑简化版

以下是使用C++11实现的TCP服务端处理逻辑,包含循环读取数据、帧头检测(AABBCC)及4376字节数据包处理:

cpp

#include <iostream>
#include <vector>
#include <cstring>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
constexpr size_t PACKET_SIZE = 4376; // 完整数据包大小(含3字节帧头)
constexpr size_t HEADER_SIZE = 3; // 帧头大小
constexpr uint8_t FRAME_HEADER[] = {0xAA, 0xBB, 0xCC}; // 帧头标识
// 查找缓冲区中的帧头位置
auto find_frame_header(const std::vector<char>& buffer) {
for (size_t i = 0; i <= buffer.size() - HEADER_SIZE; ++i) {
bool match = true;
for (size_t j = 0; j < HEADER_SIZE; ++j) {
if (static_cast<uint8_t>(buffer[i+j]) != FRAME_HEADER[j]) {
match = false;
break;
}
}
if (match) return buffer.begin() + i;
}
return buffer.end();
}
// 数据包处理函数(示例)
void process_packet(const char* data) {
// 这里添加实际业务逻辑
std::cout << "Received valid packet!" << std::endl;
}
int main() {
// 1. 创建TCP socket
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd == -1) {
std::cerr << "Socket creation failed!" << std::endl;
return 1;
}
// 2. 绑定地址
sockaddr_in server_addr{};
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(8080); // 监听端口
if (bind(server_fd, (sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
std::cerr << "Bind failed!" << std::endl;
close(server_fd);
return 1;
}
// 3. 开始监听
if (listen(server_fd, 5) == -1) {
std::cerr << "Listen failed!" << std::endl;
close(server_fd);
return 1;
}
// 4. 接受客户端连接
sockaddr_in client_addr{};
socklen_t addr_len = sizeof(client_addr);
int client_fd = accept(server_fd, (sockaddr*)&client_addr, &addr_len);
if (client_fd == -1) {
std::cerr << "Accept failed!" << std::endl;
close(server_fd);
return 1;
}
std::vector<char> buffer;
buffer.reserve(PACKET_SIZE * 2); // 预留双倍数据包空间
while (true) {
// 5. 循环接收数据
char temp_buf[1024];
ssize_t bytes_received = recv(client_fd, temp_buf, sizeof(temp_buf), 0);
if (bytes_received <= 0) {
std::cout << "Connection closed by client" << std::endl;
break;
}
// 将接收数据追加到缓冲区
buffer.insert(buffer.end(), temp_buf, temp_buf + bytes_received);
// 6. 处理缓冲区数据
while (true) {
auto header_pos = find_frame_header(buffer);
if (header_pos == buffer.end()) {
// 未找到帧头,保留最后两个字节防止丢弃可能的帧头前缀
if (buffer.size() >= HEADER_SIZE - 1) {
buffer.erase(buffer.begin(), buffer.end() - (HEADER_SIZE - 1));
} else {
buffer.clear();
}
break;
}
// 检查剩余数据是否足够
if (buffer.end() - header_pos >= PACKET_SIZE) {
// 7. 处理完整数据包
process_packet(&*header_pos);
// 8. 移除已处理数据(包含帧头)
buffer.erase(buffer.begin(), header_pos + PACKET_SIZE);
} else {
// 数据不足,等待下次接收
break;
}
}
}
// 清理资源
close(client_fd);
close(server_fd);
return 0;
}

关键实现细节说明:

  1. 缓冲区管理
    • 使用std::vector<char>作为动态缓冲区,自动管理内存
    • 预分配双倍数据包大小空间(PACKET_SIZE * 2)减少内存重分配
  2. 帧头检测
    • find_frame_header函数逐字节比对帧头模式
    • 使用uint8_t类型转换避免符号扩展问题
    • 精确匹配连续3字节的帧头序列
  3. 粘包处理
    • 当未找到完整帧头时,保留最后2字节(HEADER_SIZE - 1)防止丢弃可能的帧头前缀
    • 找到帧头后检查剩余数据是否满足完整数据包长度
  4. 数据包处理
    • 检测到完整数据包后调用process_packet处理
    • 每次处理后从缓冲区移除已处理数据(包含帧头)
  5. 异常处理
    • 检测客户端断开连接(recv返回0)
    • 基础错误检查(socket创建、绑定、监听等)

使用注意事项:

  1. 编译时需要链接网络库(Linux下添加-lpthread参数)
  2. 实际使用时需完善以下部分:
    • process_packet函数中的业务逻辑
    • 添加校验和验证(如协议需要)
    • 多客户端支持(可通过多线程/select/epoll实现)
    • 错误日志记录
    • 性能优化(环形缓冲区、零拷贝等)

该实现能够有效处理TCP粘包问题,确保完整数据包的接收和处理,适用于需要固定长度数据包传输的场景。

相关文章:

  • Vue2数组数字字段求和技巧 数字求和方法
  • 20250605在荣品的PRO-RK3566开发板的Android13下让PMIC芯片RK809在长按下开机
  • 设置存储器若干单元为相同的字节
  • CMake指令:add_definitions
  • CentOS 7 如何pip3安装pyaudio?
  • Windows下安装MySQL8.X
  • 【JVM】三色标记法原理
  • GPU加速与非加速的深度学习张量计算对比Demo,使用PyTorch展示关键差异
  • Python[数据结构及算法 --- 栈]
  • tcp/udp
  • 6月5日day45
  • Python实现markdown文件转word
  • 六、数据库的安全性
  • 书籍将正方形矩阵顺时针转动90°(8)0605
  • RADIUS-如何获取凭证
  • [蓝桥杯]植树
  • LLaMA.cpp 文本生成惩罚机制详解:从原理到实践的完整指南
  • Spring Bean生命周期全解析:从创建到销毁的底层细节
  • Docker MCP 目录和工具包简介:使用 MCP 为 AI 代理提供支持的简单安全方法
  • Flask+LayUI开发手记(八):通用封面缩略图上传实现
  • 宜昌建网站/免费域名申请网站
  • 湖北新闻网官方网站/网络营销公司名字大全
  • 做国际贸易用什么网站/超级外链在线发布
  • 博彩网站怎么做代理/在线网页生成器
  • 郑州专业做网站企业/买淘宝店铺多少钱一个
  • 分销联盟推广开放平台/沈阳网站seo排名公司