一、结构化数据传输流程
这里涉及协议定制、序列化/反序列化的知识
对于序列化和反序列化,有现成的解决方案:①json ②probuff ③xml
二、理解发送接收函数
我们调用的所有发送/接收函数,根本就不是把数据发送到网络中!本质都是拷贝函数!
Client -> Server:tcp发送的本质,就是将数据从c的发送缓冲区,拷贝到s的接收缓冲区!
Client -> Server:tcp发送的本质,就是将数据从c的发送缓冲区,拷贝到s的接收缓冲区!
每一端都有一套发送缓冲区/接收缓冲区 -> tcp是全双工的!
三、网络计算器流程
分析网络计算器的流程,就可以理解协议定制、序列化/反序列化、协议报头的作用了
说明:这里只谈论整体框架,不会细说每个函数的实现,想要完整代码的可以参考下面链接!
https://gitee.com/peter-chen-cs/linux_learning_code.git
1.定制协议
#pragma once
#include <iostream>
#include <string>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <jsoncpp/json/json.h>
// 添加报头
std::string enLength(const std::string &text)
// 去掉报头
bool deLength(const std::string &package, std::string *text)
// 请求
class Request
{
public:
// 构造函数
Request()
// 序列化
bool serialize(std::string *out)
// 反序列化
bool deserialize(const std::string &in)
public:
int _x;
int _y;
char _op; // "_x _op _y"
};
// 响应
class Response
{
public:
// 构造函数
Response()
// 序列化
bool serialize(std::string *out)
// 反序列化
bool deserialize(const std::string &in)
public:
int _exitcode; // 0表示计算成功;!0表示计算失败
int _result; // 计算结果
};
// 功能:保证读到的数据是一个完整的报文
bool recvPackage(int sock, std::string &inbuffer, std::string *text)
2.服务端
(1)calServer.hpp
// 计算服务器-用于计算
class CalServer
{
public:
// 构造函数
CalServer()
// 析构函数
~CalServer(){}
// 初始化计算服务器
void initServer()
// 启动计算服务器
void start(func_t func)
{...handlerEntery(){func_t func()}...}
private:
int _listensock;
uint16_t _port;
};
typedef std::function<bool(const Request &req, Response &resp)> func_t; // 处理业务
// 放在这里是为了保证解耦
void handlerEntery(int sock, func_t func)
{
while (true)
{
// 1.从应用层缓冲区读取一个完整报文
// 2.对请求Request反序列化-得到一个结构化的请求对象
// 3.计算处理 -- 逻辑业务:得到一个结构化响应
func(req, resp);
// 4.对响应Response进行序列化-得到一个"字符串"
// 5.添加包头,发送响应
}
}
(2)calServer.cpp
#include "calServer.hpp"
#include <memory>
bool cal(const Request &req, Response &resp)
{
// 请求已经是结构化数据了,可以直接使用
// 根据结构化请求完成计算
// 构建结构化的响应
}
int main(int argc, char *argv[])
{
// 启动服务器
unique_ptr<CalServer> tsvr(new CalServer(port));
tsvr->initServer();
tsvr->start(cal);
return 0;
}
3.客户端
(1)calClient.hpp
class CalClient
{
public:
// 构造函数
CalClient(const std::string &serverip, const uint16_t &serverport)
// 析构函数
~CalClient(){}
// 初始化客户端
void initClient()
// 启动服务端
void start()
{
// 建立连接
while (true)
{
// 输入算式,并将输入的字符串转化成Request-ParseLine()
// 将Request序列化
// 添加报头
// 发送到服务器
// --服务器处理完发回来了--
// 读取一个完整的响应
// 去掉报头
// 反序列化得到Response
}
}
// 把从键盘输入的算式转化成一个Request请求
Request ParseLine(const std::string &line)
private:
int _sock;
std::string _serverip;
uint16_t _serverport;
};
(2)calClient.cpp
#include "calClient.hpp"
#include <memory>
int main(int argc, char *argv[])
{
// 启动客户端
}