B/S 和C/S架构在服务端接收请求的方式有显著差异。
一、基本架构对比
C/S(客户端-服务器)架构
[专门的客户端程序] ← 自定义协议 → [服务端程序]
↓ ↑
TCP连接 TCP监听
二进制/自定义协议 8888端口
TCP(Transmission Control Protocol,传输控制协议)是互联网中最核心、最基础的通信协议之一。它属于传输层协议,位于IP协议之上,负责在不可靠的IP网络之上,为应用程序提供可靠的、面向连接的、基于字节流的通信服务。
B/S(浏览器-服务器)架构
[Web浏览器] ← HTTP/HTTPS协议 → [Web服务器] ← 应用协议 → [后端服务]
↓ ↑ ↓ ↑
HTTP请求 HTTP响应 Nginx/Apache 业务逻辑
80/443端口 反向代理/负载均衡
二、核心差异对比表
| 方面 | C/S架构 | B/S架构 |
|---|---|---|
| 客户端形态 | 专门开发的桌面/移动应用 | 标准Web浏览器 |
| 网络协议 | 通常为自定义二进制协议或RPC框架 | HTTP/HTTPS(应用层协议) |
| 连接方式 | 通常是长连接/连接池 | 通常是短连接 (HTTP/1.x)或长连接(HTTP/2/3) |
| 数据格式 | Protocol Buffers、Thrift、自定义二进制 | JSON/XML、Form Data、GraphQL |
| 服务发现 | 需要内置(IP:Port配置、服务注册中心) | 通过域名和DNS解析 |
| 安全机制 | 自定义加密、SSL/TLS隧道 | HTTPS、CORS、Cookie/Session、OAuth |
| 升级维护 | 需推送客户端更新 | 服务端更新即时生效 |
三、服务端接收请求的具体差异
1. C/S架构的服务端接收方式
// 典型的C/S服务端代码结构
class CS_Server {
void start() {
// 1. 监听固定端口
server_socket_.bind("0.0.0.0", 8888);
while (running) {
// 2. 接受TCP连接
ClientSocket client = server_socket_.accept();
// 3. 接收自定义协议的数据包
Packet packet = client.receivePacket();
// 4. 解析自定义二进制格式
Request req = parseCustomProtocol(packet);
// 5. 处理业务逻辑
Response resp = handleRequest(req);
// 6. 按照自定义协议格式返回
client.sendPacket(serializeResponse(resp));
}
}
};
特点:
-
直接TCP监听:在指定端口上直接监听
-
协议完全可控:自定义包头、包体格式
-
状态保持:通常保持长连接,有状态
-
高效紧凑:二进制协议,传输量小
2. B/S架构的服务端接收方式
// 典型的B/S服务端代码结构(以REST API为例)
class BS_Server {
void start() {
// 1. Web框架(如Express/Spring Boot)初始化
app = initializeWebFramework();
// 2. 定义RESTful端点(路由)
app.post("/api/data", [](const HttpRequest& req, HttpResponse& resp) {
// 3. 从HTTP请求中提取数据
std::string method = req.getMethod(); // "POST"
std::string path = req.getPath(); // "/api/data"
std::string token = req.getHeader("Authorization");
std::string body = req.getBody(); // JSON字符串
// 4. 解析JSON(而非自定义二进制)
Json json = Json::parse(body);
std::string key = json["key"];
std::string value = json["value"];
// 5. 处理业务逻辑
bool success = processBusinessLogic(key, value);
// 6. 返回HTTP响应
resp.setStatus(200);
resp.setHeader("Content-Type", "application/json");
resp.setBody(R"({"code":0,"message":"success"})");
});
// 7. 监听HTTP端口
app.listen(80);
}
};
特点:
-
通过Web服务器/框架:Nginx、Apache、Tomcat等
-
HTTP协议解析:自动解析HTTP头、方法、路径、参数
-
无状态设计:每个HTTP请求独立,依赖Cookie/Session/Token维持状态
-
文本协议:通常是JSON/XML,人类可读
四、架构差异对服务端设计的影响
连接管理
// C/S:通常维护连接池或长连接
class CS_ConnectionManager {
std::unordered_map<int, ClientConnection> active_connections_;
// 需要实现心跳、重连、连接保活逻辑
};
// B/S:通常无连接管理(HTTP短连接)
// 或由Web服务器管理(HTTP/2长连接)
协议处理
// C/S:需要手动实现协议栈
class CustomProtocol {
// 自定义的封包/解包逻辑
Packet pack(const Request& req) {
// 包头(4字节长度) + 包体(命令号+数据)
uint32_t total_len = sizeof(Header) + req.data.size();
// ... 复杂的字节序处理、校验和计算
}
};
// B/S:使用标准HTTP,框架自动处理
// 开发者只需关心业务路由和JSON解析
安全考虑
// C/S:需要自己实现全套安全机制
class CS_Security {
// 加密通信、防重放攻击、消息防篡改
// 客户端身份验证、版本兼容性检查
};
// B/S:利用成熟的Web安全机制
// HTTPS、CORS、CSRF Token、SameSite Cookie
// 防火墙、WAF等基础设施
五、现代趋势:混合与融合
1. 传统C/S的Web化
-
gRPC-Web:让浏览器能调用gRPC服务
-
WebSocket:在B/S中实现全双工长连接
// 浏览器中的WebSocket
const ws = new WebSocket("ws://server:8888/ws");
ws.send(JSON.stringify({cmd: "get", key: "user1"}));
2. B/S后端的API化
// 现在很多B/S后端本身就是API服务器
// 既服务浏览器,也服务移动端App
class UniversalAPI {
// 同一套接口,多种客户端
// 浏览器访问:GET https://api.example.com/v1/data
// 移动App访问:同样的HTTP接口
// 甚至通过API网关转换为gRPC
};
3. 微服务架构下的统一
# 在K8s微服务中,C/S和B/S的界限模糊
services:
- name: "data-service"
ports:
- 8080:8080 # HTTP接口(供B/S调用)
- 9090:9090 # gRPC接口(供C/S调用)
# 实际业务逻辑相同,只是协议适配层不同
六、实际应用场景示例
场景1:股票交易系统(C/S典型)
// 服务端
class StockServer {
// 二进制协议,高频低延迟
// 长连接,实时推送行情
// 客户端是专业的交易软件
};
场景2:电商网站(B/S典型)
# 服务端(Django/Spring Boot)
@app.route('/api/order', methods=['POST'])
def create_order():
# HTTP + JSON
# 浏览器访问,也供App调用
# 无状态,通过JWT识别用户
return jsonify({'order_id': 123})
场景3:实时协作工具(混合)
// Web版用WebSocket + HTTP
// 桌面客户端用自定义协议
// 移动端用HTTP/2 + gRPC
// 后端统一业务逻辑,不同协议适配
总结
| 对比维度 | C/S架构接收方式 | B/S架构接收方式 |
|---|---|---|
| 协议层 | 传输层/自定义应用层 | HTTP应用层协议 |
| 连接模型 | 主动长连接 | 请求-响应短连接 |
| 数据格式 | 紧凑二进制 | 文本(JSON/XML) |
| 服务入口 | IP:Port直接暴露 | 通过Web服务器/反向代理 |
| 客户端耦合 | 强耦合,协议升级需同步 | 松耦合,接口兼容即可 |
| 适用场景 | 高性能、实时性要求高 | 跨平台、易部署、广域网 |
现代实践:实际上两者界限越来越模糊。很多系统同时提供:
-
HTTP API 给Web和移动端
-
gRPC/自定义协议 给内部服务或专业客户端
-
WebSocket 给需要实时性的Web应用
服务端设计的关键是分离协议层和业务层 ,让同一套业务逻辑能够通过不同的协议适配器对外提供服务。这正是您最初设计的DataStorageServer可以做到的------核心存储引擎是统一的,只是接入协议不同。