项目背景详细介绍
在所有网络通信技术中,TCP 通讯是最基础、最核心、也是最重要的一种通信方式。
无论是:
Web 服务(HTTP / HTTPS)
数据库连接(MySQL / Redis)
微服务通信(RPC / gRPC 底层)
即时通信系统
游戏服务器
分布式系统
其底层几乎全部依赖 TCP 协议。
TCP 的核心特性包括:
面向连接
可靠传输
有序到达
流量控制
拥塞控制
这使得 TCP 成为绝大多数工程级网络系统的首选协议。
对于 C++ 开发者而言:
不会 TCP Socket 编程,就无法真正进入系统级 / 后台开发领域
然而,TCP 编程对初学者并不友好:
API 偏底层
概念多(端口、IP、连接、阻塞等)
调用流程严格
出错难以调试
因此,本项目的目标是:
用一个完整、清晰、可运行的 C++ TCP 客户端 / 服务器示例,系统讲透 TCP 通讯的工程实现方式
该示例可直接用于:
Linux 网络编程教学
博客系统文章
面试 Socket 编程
后续高并发服务器(epoll / reactor)学习基础
项目需求详细介绍
1. 功能需求
实现 TCP 服务器
实现 TCP 客户端
支持双向通信
支持多次消息发送
正确处理连接与断开
2. 技术要求
使用 POSIX Socket API
基于 IPv4
使用阻塞 IO(便于教学)
支持 Linux / Unix 系统
3. 教学与工程要求
严格遵循 TCP 建立流程
代码结构清晰、可扩展
每个系统调用用途明确
可作为后续 epoll / 多线程改造基础
相关技术详细介绍
1. TCP 通讯模型
经典 TCP 通讯采用客户端 / 服务器模型:
Server:监听端口,等待连接
Client:主动发起连接
基本流程如下:
服务器端:
socket
bind
listen
accept
recv / send
客户端:
socket
connect
send / recv
2. Socket 是什么
Socket 是操作系统提供的一种:
进程间网络通信抽象接口
它屏蔽了底层网络细节,使程序可以像操作文件一样进行网络通信。
3. 阻塞 IO 的特点
调用
recv()时如果没有数据,会阻塞实现简单
不适合高并发
非常适合教学与理解 TCP 流程
实现思路详细介绍
本项目采用最基础、最清晰的阻塞式 TCP 通讯模型:
定义 TCPServer 与 TCPClient 类
服务器端:
创建监听 Socket
接收客户端连接
循环接收并回复消息
客户端:
连接服务器
循环发送并接收数据
使用字符串作为通信内容
所有错误进行简单处理
该实现:
逻辑直观
调用顺序清晰
易于调试
是后续所有网络模型的“母版”
完整实现代码
/**************************************************** * File: TCPServer.h ****************************************************/ #pragma once #include <string> class TCPServer { public: TCPServer(int port); ~TCPServer(); void start(); private: int m_port; int m_listenFd; }; /**************************************************** * File: TCPServer.cpp ****************************************************/ #include "TCPServer.h" #include <arpa/inet.h> #include <unistd.h> #include <cstring> #include <iostream> TCPServer::TCPServer(int port) : m_port(port), m_listenFd(-1) { } TCPServer::~TCPServer() { if (m_listenFd != -1) close(m_listenFd); } void TCPServer::start() { // 创建 socket m_listenFd = socket(AF_INET, SOCK_STREAM, 0); sockaddr_in addr{}; addr.sin_family = AF_INET; addr.sin_port = htons(m_port); addr.sin_addr.s_addr = INADDR_ANY; // 绑定端口 bind(m_listenFd, (sockaddr*)&addr, sizeof(addr)); // 监听 listen(m_listenFd, 5); std::cout << "Server listening on port " << m_port << std::endl; // 接受客户端连接 int clientFd = accept(m_listenFd, nullptr, nullptr); std::cout << "Client connected" << std::endl; char buffer[1024]; while (true) { memset(buffer, 0, sizeof(buffer)); int len = recv(clientFd, buffer, sizeof(buffer), 0); if (len <= 0) break; std::cout << "Client: " << buffer << std::endl; std::string reply = "Server received: "; reply += buffer; send(clientFd, reply.c_str(), reply.size(), 0); } close(clientFd); } /**************************************************** * File: TCPClient.h ****************************************************/ #pragma once #include <string> class TCPClient { public: TCPClient(const std::string& ip, int port); ~TCPClient(); void start(); private: std::string m_ip; int m_port; int m_sockFd; }; /**************************************************** * File: TCPClient.cpp ****************************************************/ #include "TCPClient.h" #include <arpa/inet.h> #include <unistd.h> #include <cstring> #include <iostream> TCPClient::TCPClient(const std::string& ip, int port) : m_ip(ip), m_port(port), m_sockFd(-1) { } TCPClient::~TCPClient() { if (m_sockFd != -1) close(m_sockFd); } void TCPClient::start() { // 创建 socket m_sockFd = socket(AF_INET, SOCK_STREAM, 0); sockaddr_in addr{}; addr.sin_family = AF_INET; addr.sin_port = htons(m_port); inet_pton(AF_INET, m_ip.c_str(), &addr.sin_addr); // 连接服务器 connect(m_sockFd, (sockaddr*)&addr, sizeof(addr)); std::cout << "Connected to server" << std::endl; char buffer[1024]; while (true) { std::string msg; std::cout << "Input: "; std::getline(std::cin, msg); if (msg == "exit") break; send(m_sockFd, msg.c_str(), msg.size(), 0); memset(buffer, 0, sizeof(buffer)); recv(m_sockFd, buffer, sizeof(buffer), 0); std::cout << buffer << std::endl; } } /**************************************************** * File: server_main.cpp ****************************************************/ #include "TCPServer.h" int main() { TCPServer server(8888); server.start(); return 0; } /**************************************************** * File: client_main.cpp ****************************************************/ #include "TCPClient.h" int main() { TCPClient client("127.0.0.1", 8888); client.start(); return 0; }代码详细解读(仅解读方法作用)
TCPServer
封装 TCP 服务器逻辑,负责监听端口并处理客户端连接。
start(Server)
完成 socket 创建、绑定、监听、接收连接以及数据收发。
TCPClient
封装 TCP 客户端逻辑,负责连接服务器并进行通信。
start(Client)
建立 TCP 连接并进行双向消息通信。
socket / bind / listen / accept
TCP 服务器端建立连接的标准调用流程。
connect
客户端向服务器发起连接请求。
项目详细总结
通过本项目,你可以系统掌握:
TCP 协议在工程中的真实使用方式
Linux Socket 编程完整流程
客户端 / 服务器模型
后续高并发网络编程的基础能力
这是所有 C++ 后台、系统、网络方向的必修项目。
项目常见问题及解答
Q1:为什么 recv 返回 0?
A:表示对端正常关闭连接。
Q2:可以支持多个客户端吗?
A:可以,需引入多线程或 epoll。
Q3:为什么要使用 htons?
A:保证网络字节序一致性。
扩展方向与性能优化
多线程 TCP 服务器
epoll / Reactor 模型
TCP 粘包 / 拆包处理
心跳机制
SSL / TLS 加密通信