news 2026/6/24 8:12:22

C++:实现echo服务端和客户端(附带源码)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++:实现echo服务端和客户端(附带源码)

一、项目背景详细介绍

在网络编程学习中,Echo(回显)服务是最经典、也是最重要的入门示例之一。

所谓Echo 服务,指的是:

客户端发送什么数据,服务端原样返回什么数据

虽然功能非常简单,但它几乎覆盖了TCP 网络编程的全部核心知识点

  • 客户端 / 服务端模型

  • TCP 三次握手

  • 套接字创建与关闭

  • 阻塞式 I/O

  • 字节流的收发过程

  • 多客户端并发的基础思路

在真实工程中,Echo 服务常用于:

  • 网络连通性测试

  • 性能压测基准

  • 协议调试

  • 网络框架最小可运行原型(MVP)

C++ 学习角度来看,实现一个 Echo 服务可以系统训练:

  • Linux Socket API 使用

  • 字符缓冲区管理

  • 错误处理与边界判断

  • 客户端与服务端解耦设计

因此,本项目的目标是:

使用 C++ 从零实现一个完整、可运行、可教学的 Echo 服务端和客户端


二、项目需求详细介绍

2.1 功能需求

服务端(Echo Server)

  1. 监听指定端口

  2. 接受客户端 TCP 连接

  3. 接收客户端发送的数据

  4. 将接收到的数据原样返回给客户端

  5. 支持客户端断开连接


客户端(Echo Client)

  1. 连接服务端

  2. 从终端读取用户输入

  3. 将输入发送给服务端

  4. 接收服务端回显数据并显示

  5. 支持主动退出


2.2 技术要求

  • 使用TCP 协议

  • 基于Linux / Unix Socket API

  • 阻塞式通信(便于教学)

  • 服务端与客户端逻辑清晰分离

  • 所有代码集中在一个代码块

  • 使用注释模拟多文件结构

  • 所有函数提供详细中文注释


2.3 教学要求

  • 代码结构清晰、易读

  • 注释解释“为什么这样写”

  • 可直接复制编译运行

  • 适合作为网络编程第一课项目


三、相关技术详细介绍

3.1 TCP 网络通信模型

TCP 通信是一个典型的客户端 / 服务端模型

Client -----> Server | | send recv recv send

核心流程如下:

服务端流程

  1. socket()—— 创建监听套接字

  2. bind()—— 绑定 IP 和端口

  3. listen()—— 进入监听状态

  4. accept()—— 接受客户端连接

  5. recv()/send()—— 数据通信


客户端流程

  1. socket()—— 创建套接字

  2. connect()—— 连接服务端

  3. send()—— 发送数据

  4. recv()—— 接收回显


3.2 阻塞式 I/O 特点

  • recv()在无数据时会阻塞

  • send()在缓冲区满时可能阻塞

  • 优点:逻辑简单、易理解

  • 缺点:并发能力有限(后续可优化)


3.3 字节流通信特点

TCP 是字节流协议

  • 没有消息边界

  • 一次send≠ 一次recv

  • Echo 服务中直接原样返回即可


四、实现思路详细介绍

4.1 总体设计思路

  1. 使用一个程序同时支持:

    • Echo 服务端模式

    • Echo 客户端模式

  2. 通过命令行选择运行模式

  3. 服务端使用循环处理客户端(单客户端版,便于教学)

  4. 客户端循环发送并接收数据


4.2 服务端处理流程

  1. 创建监听 socket

  2. 绑定端口并监听

  3. 接受客户端连接

  4. 循环:

    • 接收数据

    • 直接发送回客户端

  5. 客户端断开后关闭连接


4.3 客户端处理流程

  1. 连接服务端

  2. 从终端读取一行输入

  3. 发送给服务端

  4. 接收回显数据并打印

  5. 输入quit退出


五、完整实现代码

/**************************************************** * 文件名:Echo.cpp * 描述:C++ Echo 服务端 & 客户端(教学示例) ****************************************************/ #include <iostream> #include <string> #include <cstring> #include <unistd.h> #include <arpa/inet.h> #include <netinet/in.h> using namespace std; const int PORT = 8888; const int BUFFER_SIZE = 1024; /**************************************************** * Echo 服务端实现 ****************************************************/ void runEchoServer() { // 1. 创建监听套接字 int listenFd = socket(AF_INET, SOCK_STREAM, 0); if (listenFd < 0) { cerr << "socket 创建失败" << endl; return; } // 2. 绑定地址和端口 sockaddr_in serverAddr{}; serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(PORT); serverAddr.sin_addr.s_addr = INADDR_ANY; if (bind(listenFd, (sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) { cerr << "bind 失败" << endl; close(listenFd); return; } // 3. 开始监听 if (listen(listenFd, 5) < 0) { cerr << "listen 失败" << endl; close(listenFd); return; } cout << "Echo 服务端启动,监听端口 " << PORT << endl; // 4. 接受客户端连接 sockaddr_in clientAddr{}; socklen_t clientLen = sizeof(clientAddr); int connFd = accept(listenFd, (sockaddr*)&clientAddr, &clientLen); if (connFd < 0) { cerr << "accept 失败" << endl; close(listenFd); return; } cout << "客户端已连接" << endl; char buffer[BUFFER_SIZE]; // 5. Echo 处理循环 while (true) { memset(buffer, 0, BUFFER_SIZE); // 接收客户端数据 int bytes = recv(connFd, buffer, BUFFER_SIZE, 0); if (bytes <= 0) { cout << "客户端断开连接" << endl; break; } cout << "收到数据:" << buffer << endl; // 原样返回(Echo) send(connFd, buffer, bytes, 0); } // 6. 关闭连接 close(connFd); close(listenFd); } /**************************************************** * Echo 客户端实现 ****************************************************/ void runEchoClient(const string& serverIp) { // 1. 创建套接字 int sockFd = socket(AF_INET, SOCK_STREAM, 0); if (sockFd < 0) { cerr << "socket 创建失败" << endl; return; } // 2. 配置服务器地址 sockaddr_in serverAddr{}; serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(PORT); inet_pton(AF_INET, serverIp.c_str(), &serverAddr.sin_addr); // 3. 连接服务器 if (connect(sockFd, (sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) { cerr << "connect 失败" << endl; close(sockFd); return; } cout << "已连接到 Echo 服务端" << endl; char buffer[BUFFER_SIZE]; string input; // 4. 发送与接收循环 while (true) { cout << "请输入内容(quit退出): "; getline(cin, input); if (input == "quit") { break; } // 发送数据 send(sockFd, input.c_str(), input.size(), 0); // 接收回显 memset(buffer, 0, BUFFER_SIZE); int bytes = recv(sockFd, buffer, BUFFER_SIZE, 0); if (bytes <= 0) { cout << "服务器断开连接" << endl; break; } cout << "Echo 返回:" << buffer << endl; } // 5. 关闭套接字 close(sockFd); } /**************************************************** * 主函数 ****************************************************/ int main() { cout << "请选择运行模式 (1-服务端 2-客户端): "; int mode; cin >> mode; cin.ignore(); if (mode == 1) { runEchoServer(); } else if (mode == 2) { string ip; cout << "请输入服务器IP: "; cin >> ip; cin.ignore(); runEchoClient(ip); } return 0; }

六、代码详细解读(仅解读方法作用)

  • runEchoServer:启动 Echo 服务端,接收并原样返回客户端数据

  • runEchoClient:连接服务端,发送数据并接收回显

  • socket:创建 TCP 套接字

  • bind / listen / accept:服务端三步走

  • connect:客户端发起连接

  • send / recv:完成数据通信


七、项目详细总结

通过本项目,你已经完整掌握:

  • TCP 客户端 / 服务端通信流程

  • Linux Socket API 的核心使用方式

  • 阻塞式 I/O 通信模型

  • 字节流收发的基本规律

  • 网络程序的最小可运行结构

这是后续学习:

  • 多客户端并发服务器

  • epoll / select

  • 高性能网络框架

  • RPC / HTTP 服务器

必经基础项目


八、项目常见问题及解答

Q1:为什么 recv 返回 0?
A:表示对端正常关闭连接。

Q2:一次 send 一定对应一次 recv 吗?
A:不一定,TCP 是字节流协议。

Q3:为什么服务端只能处理一个客户端?
A:这是教学简化版本,后续可扩展为多线程或 epoll。


九、扩展方向与性能优化

  1. 支持多客户端并发(多线程 / epoll)

  2. 添加消息长度协议

  3. 非阻塞 I/O

  4. 日志系统

  5. 封装为网络库

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/20 8:52:45

C++:实现BCC校验计算(附带源码)

一、项目背景详细介绍在底层通信、嵌入式开发以及工业控制领域中&#xff0c;数据可靠性 是一个永恒的主题。在以下典型场景中&#xff1a;串口通信&#xff08;UART / RS232 / RS485&#xff09;工业总线&#xff08;Modbus / 自定义协议&#xff09;传感器数据采集MCU ↔ 上位…

作者头像 李华
网站建设 2026/6/20 7:01:36

零基础玩转通义千问2.5:vLLM离线推理保姆级教程

零基础玩转通义千问2.5&#xff1a;vLLM离线推理保姆级教程 1. 引言&#xff1a;为什么选择 vLLM Qwen2.5-7B-Instruct&#xff1f; 在大模型落地应用的实践中&#xff0c;高效、低成本、可本地部署的推理方案是开发者最关心的核心问题。通义千问2.5系列中的 Qwen2.5-7B-Ins…

作者头像 李华
网站建设 2026/6/20 8:54:03

实战演示:用麦橘超然Flux生成赛博朋克风城市街景

实战演示&#xff1a;用麦橘超然Flux生成赛博朋克风城市街景 1. 引言&#xff1a;AI图像生成的本地化实践新选择 随着生成式AI技术的快速发展&#xff0c;高质量图像生成已不再局限于云端服务。在边缘设备或本地环境中运行大模型成为越来越多开发者和创作者的需求。然而&…

作者头像 李华
网站建设 2026/6/20 8:54:17

FSMN VAD金融风控应用:电话销售合规话术检测支持

FSMN VAD金融风控应用&#xff1a;电话销售合规话术检测支持 1. 引言 在金融行业的电话销售场景中&#xff0c;合规性是监管机构和企业自身极为关注的核心问题。销售人员是否完整告知风险、是否存在误导性陈述、是否遗漏关键条款说明&#xff0c;这些都直接关系到企业的法律风…

作者头像 李华
网站建设 2026/6/20 8:51:36

Qwen3-14B实战教程:从零开始部署企业级智能客服系统

Qwen3-14B实战教程&#xff1a;从零开始部署企业级智能客服系统 1. 引言 随着人工智能技术的快速发展&#xff0c;大型语言模型&#xff08;LLM&#xff09;在企业服务中的应用日益广泛。智能客服作为企业与用户交互的重要窗口&#xff0c;正逐步由规则驱动向AI驱动演进。Qwe…

作者头像 李华
网站建设 2026/6/19 8:35:26

STM32串口DMA接收不定长数据核心要点

STM32串口DMA接收不定长数据&#xff1a;从原理到实战的深度拆解你有没有遇到过这样的场景&#xff1f;设备通过串口源源不断发来数据&#xff0c;长度忽长忽短——可能是传感器的一帧采样&#xff0c;也可能是JSON格式的配置指令。用传统中断方式接收&#xff1f;高波特率下CP…

作者头像 李华