爆款云主机2核4G限时秒杀,88元/年起!
查看详情

活动

天翼云最新优惠活动,涵盖免费试用,产品折扣等,助您降本增效!
热门活动
  • 618智算钜惠季 爆款云主机2核4G限时秒杀,88元/年起!
  • 免费体验DeepSeek,上天翼云息壤 NEW 新老用户均可免费体验2500万Tokens,限时两周
  • 云上钜惠 HOT 爆款云主机全场特惠,更有万元锦鲤券等你来领!
  • 算力套餐 HOT 让算力触手可及
  • 天翼云脑AOne NEW 连接、保护、办公,All-in-One!
  • 中小企业应用上云专场 产品组合下单即享折上9折起,助力企业快速上云
  • 息壤高校钜惠活动 NEW 天翼云息壤杯高校AI大赛,数款产品享受线上订购超值特惠
  • 天翼云电脑专场 HOT 移动办公新选择,爆款4核8G畅享1年3.5折起,快来抢购!
  • 天翼云奖励推广计划 加入成为云推官,推荐新用户注册下单得现金奖励
免费活动
  • 免费试用中心 HOT 多款云产品免费试用,快来开启云上之旅
  • 天翼云用户体验官 NEW 您的洞察,重塑科技边界

智算服务

打造统一的产品能力,实现算网调度、训练推理、技术架构、资源管理一体化智算服务
智算云(DeepSeek专区)
科研助手
  • 算力商城
  • 应用商城
  • 开发机
  • 并行计算
算力互联调度平台
  • 应用市场
  • 算力市场
  • 算力调度推荐
一站式智算服务平台
  • 模型广场
  • 体验中心
  • 服务接入
智算一体机
  • 智算一体机
大模型
  • DeepSeek-R1-昇腾版(671B)
  • DeepSeek-R1-英伟达版(671B)
  • DeepSeek-V3-昇腾版(671B)
  • DeepSeek-R1-Distill-Llama-70B
  • DeepSeek-R1-Distill-Qwen-32B
  • Qwen2-72B-Instruct
  • StableDiffusion-V2.1
  • TeleChat-12B

应用商城

天翼云精选行业优秀合作伙伴及千余款商品,提供一站式云上应用服务
进入甄选商城进入云市场创新解决方案
办公协同
  • WPS云文档
  • 安全邮箱
  • EMM手机管家
  • 智能商业平台
财务管理
  • 工资条
  • 税务风控云
企业应用
  • 翼信息化运维服务
  • 翼视频云归档解决方案
工业能源
  • 智慧工厂_生产流程管理解决方案
  • 智慧工地
建站工具
  • SSL证书
  • 新域名服务
网络工具
  • 翼云加速
灾备迁移
  • 云管家2.0
  • 翼备份
资源管理
  • 全栈混合云敏捷版(软件)
  • 全栈混合云敏捷版(一体机)
行业应用
  • 翼电子教室
  • 翼智慧显示一体化解决方案

合作伙伴

天翼云携手合作伙伴,共创云上生态,合作共赢
天翼云生态合作中心
  • 天翼云生态合作中心
天翼云渠道合作伙伴
  • 天翼云代理渠道合作伙伴
天翼云服务合作伙伴
  • 天翼云集成商交付能力认证
天翼云应用合作伙伴
  • 天翼云云市场合作伙伴
  • 天翼云甄选商城合作伙伴
天翼云技术合作伙伴
  • 天翼云OpenAPI中心
  • 天翼云EasyCoding平台
天翼云培训认证
  • 天翼云学堂
  • 天翼云市场商学院
天翼云合作计划
  • 云汇计划
天翼云东升计划
  • 适配中心
  • 东升计划
  • 适配互认证

开发者

开发者相关功能入口汇聚
技术社区
  • 专栏文章
  • 互动问答
  • 技术视频
资源与工具
  • OpenAPI中心
开放能力
  • EasyCoding敏捷开发平台
培训与认证
  • 天翼云学堂
  • 天翼云认证
魔乐社区
  • 魔乐社区

支持与服务

为您提供全方位支持与服务,全流程技术保障,助您轻松上云,安全无忧
文档与工具
  • 文档中心
  • 新手上云
  • 自助服务
  • OpenAPI中心
定价
  • 价格计算器
  • 定价策略
基础服务
  • 售前咨询
  • 在线支持
  • 在线支持
  • 工单服务
  • 建议与反馈
  • 用户体验官
  • 服务保障
  • 客户公告
  • 会员中心
增值服务
  • 红心服务
  • 首保服务
  • 客户支持计划
  • 专家技术服务
  • 备案管家

了解天翼云

天翼云秉承央企使命,致力于成为数字经济主力军,投身科技强国伟大事业,为用户提供安全、普惠云服务
品牌介绍
  • 关于天翼云
  • 智算云
  • 天翼云4.0
  • 新闻资讯
  • 天翼云APP
基础设施
  • 全球基础设施
  • 信任中心
最佳实践
  • 精选案例
  • 超级探访
  • 云杂志
  • 分析师和白皮书
  • 天翼云·创新直播间
市场活动
  • 2025智能云生态大会
  • 2024智算云生态大会
  • 2023云生态大会
  • 2022云生态大会
  • 天翼云中国行
天翼云
  • 活动
  • 智算服务
  • 产品
  • 解决方案
  • 应用商城
  • 合作伙伴
  • 开发者
  • 支持与服务
  • 了解天翼云
      • 文档
      • 控制中心
      • 备案
      • 管理中心

      【网络编程】序列化与反序列化

      首页 知识中心 软件开发 文章详情页

      【网络编程】序列化与反序列化

      2024-05-29 07:56:46 阅读次数:39

      linux,网络,网络协议

      一、网络协议

      网络协议 是通信计算机双方必须共同遵从的一组约定,为了使数据在网络上能够从源地址到目的地址,网络通信的参与方必须遵循相同的规则,因此我们将这套规则称为协议,协议最终需要通过计算机语言的方式表示出来。


      二、序列化和反序列化

      1. 结构化数据

      如果需要传输的数据是字符串,那么我们可以直接将这个字符串发送到网络当中。但是如果我们传输的是一些结构化的数据,此时就不能直接将这些数据发送到网络当中。

      如果服务器将这些结构化的数据单独一个一个发送到网络当中,那么服务器从网络当中获取这些数据时也只能一个一个获取,并且结构化的数据往往具有特定的格式和规范,例如数据库表格或者特定的数据模型。如果直接将这些数据发送到网络,服务端可能需要处理大量复杂的格式转换和数据清洗工作,而且还有可能会影响数据的正确性。所以客户端最好把这些结构化的数据打包后统一发送到网络当中,此时服务端每次从网络当中获取到的就是一个完整的请求数据。

      常见的打包方式:

      1. 将结构化的数据组合成一个字符串:
        客户端可以按照某种方式将这些结构化的数据组合成一个字符串,然后将该字符串发送到网络当中,当服务器接收到这个字符串时,以相同的方式将这个字符串进行解析。就可以从这个字符串中提取出这些结构化的数据。

      2. 定制结构体 + 序列化与反序列化
        客户端可以定制一个结构体,将需要交互的信息定义到这个结构体当中。客户端发送数据时先对数据进行序列化,服务端接收到数据后在对其进行反序列化,此时服务端就能得到客户端发送过来的结构体了。


      2. 序列化和反序列化

      • 序列化: 将对象的状态信息转换为可以存储或传输的形式的过程。
      • 反序列化: 将字节序列恢复为的过程。

      OSI七层模型中表示层的作用就是,实现设备固有数据格式和网络标准数据格式的转换。其中设备固有的数据格式指的是数据在应用层上的格式,而网络标准数据格式则指的是序列化之后可以进行网络传输的数据格式。

      💕 序列化和反序列化的目的:

      序列化的目的是方便网络数据的发送和接收,无论何种类型的数据,经过序列化后都变成了二进制序列,此时底层在进行网络传输时看到的都是二进制序列。

      序列化后的二进制序列只有在网络传输时能够被底层识别,上层应用是无法识别序列化后的二进制数据的,因此需要将从网络中获取到的数据进行反序列化,将二进制序列的数据转换成应用层能够识别的数据格式。

      【网络编程】序列化与反序列化


      三、网络版计算器

      1. 协议定制

      💕 请求数据和响应数据

      这里我们实现一个请求结构体和一个响应结构体。

      • 请求数据结构体中包含两个操作数和一个操作符,操作数表示需要进行计算的两个数,操作符表示是要进行 +-*/ 中的哪一个操作。
      • 响应数据结构体需要包含一个计算结果和一个状态码,表示本次计算的结果和计算状态。

      状态码所表示的含义:

      • 0 表示计算成功
      • 1 表示出现除0错误
      • 2 表示模0错误
      • 3 表示非法计算

      因为协议定制好以后要被客户端和服务端同时遵守,所以需要将它写到一个头文件中,同时被客户端和服务端包含该头文件。

      // 请求
      class Request
      {
      public:
      	Request()
      	{}
      	Request(int x, int y, char op):_x(x), _y(y), _op(op)
      	{}
      public:	
      	int _x;
      	int _y;
      	char _op;
      };
      
      // 响应
      class Response
      {
      public:
      	Response()
      	{}
      	Response(int result, int code):_result(result), _code(code)
      	{}
      public:
      	int _result;
      	int _code;
      };
      

      💕 自定义序列化和反序列化

      【网络编程】序列化与反序列化
      【网络编程】序列化与反序列化
      【网络编程】序列化与反序列化

      请求序列化

      【网络编程】序列化与反序列化
      请求反序列化

      【网络编程】序列化与反序列化

      响应序列化

      【网络编程】序列化与反序列化

      响应反序列化

      【网络编程】序列化与反序列化


      💕 添加报头和去除报头

      为了保证服务器在接收时能够接收到一个完整的报文,我们需要给已经序列化完成的字符串添加报头。此报头来标识服务器读取到的数据是否是完整的,因此我们在序列化后的字符串前面添加要发送的字符串的长度,以便于服务器读取到完整的报文。

      添加报头

      【网络编程】序列化与反序列化

      去除报头

      【网络编程】序列化与反序列化

      去除报头


      2. 客户端处理收到的数据

      当客户端收到已经反序列化完成之后的数据后,需要将其分隔到数组里面,然后在转换为结构化的数据类型进行计算。

      服务器收到去除字符串报头后的结果,需要将其分隔并反序列化

      【网络编程】序列化与反序列化
      客户端收到去除字符串报头后的结果,需要将其分隔并反序列化

      【网络编程】序列化与反序列化


      3. 整体代码

      💕 Sock.hpp

      #pragma once
      
      #include <iostream>
      #include <string>
      #include <cstdlib>
      #include <cstring>
      #include <sys/types.h>          /* See NOTES */
      #include <sys/socket.h>
      #include <netinet/in.h>
      #include <arpa/inet.h>
      #include "Log.hpp"
      #include "Err.hpp"
      
      using namespace std;
      static const int gbacklog = 32;
      static const int defaultfd = -1;
      
      class Sock
      {
      public:
      	Sock():_sock(defaultfd)
      	{}
      
      	Sock(int sock):_sock(sock)
      	{}
      	
      	// 创建套接字
      	void Socket()
      	{
      		_sock = socket(AF_INET, SOCK_STREAM, 0);
      		if(_sock < 0)
      		{
      			logMessage(Fatal, "socket error, code: %d, errstring: %s", errno, strerror(errno));
      			exit(SOCKET_ERR);
      		}
      	}
      
      	// 绑定端口号 和 ip地址
      	void Bind(const uint16_t& port)
      	{
      		struct sockaddr_in local;
      		local.sin_addr.s_addr = INADDR_ANY; // 绑定任意IP地址
      		local.sin_port = htons(port); // 绑定端口号
      		local.sin_family = AF_INET;
      
      		if(bind(_sock, (struct sockaddr*)&local, sizeof(local)) < 0)
      		{
      			logMessage(Fatal, "bind error, code: %d, errstring: %s", errno, strerror(errno));
      			exit(BIND_ERR);
      		}
      	}
      
      	// 监听
      	void Listen()
      	{
      		if(listen(_sock, gbacklog) < 0)
      		{
      			logMessage(Fatal, "listen error, code: %d, errstring: %s", errno, strerror(errno));
      			exit(LISTEN_ERR);
      		}
      	}
      
      	// 获取连接
      	int Accept(string* clientip, uint16_t* clientport)
      	{
      		struct sockaddr_in temp;
      		socklen_t len = sizeof(temp);
      
      		int sock = accept(_sock, (struct sockaddr*)&temp, &len);
      		if(sock < 0)
      		{
      			logMessage(Warning, "accept error, code: %d, errstring: %s", errno, strerror(errno));
      		}
      		else
      		{
      			*clientip = inet_ntoa(temp.sin_addr);
      			*clientport = ntohs(temp.sin_port);
      		}
      		return sock;
      	}
      
      	// 客户端和服务器建立连接
      	int Connect(const string& serverip, const uint16_t& serverport)
      	{
      		struct sockaddr_in server;
      		memset(&server, 0, sizeof(server));
      		server.sin_family = AF_INET;
      		server.sin_port = htons(serverport);
      		server.sin_addr.s_addr = inet_addr(serverip.c_str());
      		
      		return connect(_sock, (struct sockaddr*)&server, sizeof(server));
      	}
      
      	int Fd()
      	{
      		return _sock;
      	}
      
      	void Close()
      	{
      		if(_sock != defaultfd)
      			close(_sock);
      	}
      	~Sock()
          {}
      
      private:
      	int _sock;
      };
      

      💕 Protocol.hpp

      #pragma once
      #include <iostream>
      #include <string>
      #include <vector>
      #include <cstring>
      #include <jsoncpp/json/json.h>
      #include "Util.hpp"
      // 给网络版本计算器定制协议
      
      // #define MYSELF 1
      
      // 给网络版本计算器定制协议
      namespace protocol_ns
      {
      	#define SEP " "
          #define SEP_LEN strlen(SEP) // 注意不能写成 sizeof
          #define HEADER_SEP "\r\n"
          #define HEADER_SEP_LEN strlen("\r\n")
      
      	// 添加报头后 —— "长度"\r\n""_x _op _y"\r\n 
      	string AddHeader(const string& str)
      	{
      		std::cout << "AddHeader 之前:\n"
                        << str << std::endl;
      
      		string s = to_string(str.size());
      		s += HEADER_SEP;
      		s += str;
      		s += HEADER_SEP;
      
      		std::cout << "AddHeader 之后:\n"
                        << s << std::endl;
      
      		return s;
      	}
      
      	// 去除报头 "长度"\r\n""_x _op _y"\r\n —— _x _op _y
      	string RemoveHeader(const std::string &str, int len)
          {
      		std::cout << "RemoveHeader 之前:\n"
                        << str << std::endl;
      
      		string res = str.substr(str.size() - HEADER_SEP_LEN - len, len);
      		return res;
      
      		std::cout << "RemoveHeader 之后:\n"
                        << res << std::endl;
          }
      
      	int ReadPackage(int sock, string& inbuffer, string*package)
      	{
      		std::cout << "ReadPackage inbuffer 之前:\n"
                        << inbuffer << std::endl;
      
      		// 边读取
      		char buffer[1024];
      		ssize_t s = recv(sock, buffer, sizeof(buffer - 1), 0);
      
      		if(s <= 0)
      			return -1;
      		buffer[s] = 0;
      		inbuffer += buffer;
      
      		std::cout << "ReadPackage inbuffer 之中:\n"
                        << inbuffer << std::endl;
      
      		// 边读取边分析, "7"\r\n""10 + 20"\r\n
      		auto pos = inbuffer.find(HEADER_SEP); // 查找 \r\n
      		if(pos == string::npos)
      			return 0;
      		
      		string lenStr = inbuffer.substr(0, pos); // 获取头部字符串
      		int len = Util::toInt(lenStr);
      
      		int targetPackageLen = lenStr.size() + len + 2 * HEADER_SEP_LEN; // 获取到的完整字符串的长度
      		if(inbuffer.size() < targetPackageLen)
      			return 0;
      		*package = inbuffer.substr(0, targetPackageLen);
      		inbuffer.erase(0, targetPackageLen);		
      		
      		std::cout << "ReadPackage inbuffer 之后:\n"
                        << inbuffer << std::endl;
      
      		return len; // 返回有效载荷的长度
      	}
      
      	// Request && Response都要提供序列化和反序列化功能——自己手写
      
      	// 请求
      	class Request
          {
      	public:
      		Request()
      		{}
      		Request(int x, int y, char op):_x(x), _y(y), _op(op)
      		{}
      		
      		// 协议的序列化 struct -> string
      		bool Serialize(string* outStr)
      		{
      			*outStr = "";
      #ifdef MYSELF
      			string x_string = to_string(_x);
      			string y_string = to_string(_y);
      
      			// 手动序列化
      			*outStr = x_string + SEP + _op + SEP + y_string;
      
      			std::cout << "Request Serialize:\n"
                            << *outStr << std::endl;
      #else
      			Json::Value root; // Value 是一种万能对象, 可以接受任意的kv类型
      			root["x"] = _x;
      			root["y"] = _y;
      			root["op"] = _op;
      
      			// Json::FastWriter writer; // Writer 是用来序列化的, struct -> string
      			Json::StyledWriter writer;
      			*outStr = writer.write(root);
      #endif
      			return true;
      		}
      
      		// 协议的反序列化 string -> struct
      		bool Deserialize(const string& inStr)
      		{
      #ifdef MYSELF
      			// 将inStr分隔到数组里面 -> [0]=>10 [1]=>+ [2]=>20
      			vector<string> result;
      			Util::StringSplit(inStr, SEP, &result);
      			if(result.size() != 3)
      				return false;
      			if(result[1].size() != 1)
      				return false;
      			
      			_x = Util::toInt(result[0]);
      			_y = Util::toInt(result[2]);
      			_op = result[1][0];
      #else
      			Json::Value root;
      			Json::Reader reader; // Reader是用来进行反序列化的
      			reader.parse(inStr, root);
      
      			_x  = root["x"].asInt();
      			_y = root["y"].asInt();
      			_op = root["op"].asInt();
      #endif
      			return true;
      		}
      		~Request()
      		{}
      	
      	public:	
      		int _x; // 操作数 _x
      		int _y; // 操作数 _y
      		char _op;// 操作符 _op
      	};
      
      	// 响应
      	class Response
      	{
      	public:
      		Response()
      		{}
      		Response(int result, int code):_result(result), _code(code)
      		{}
      
      		bool Serialize(string* outStr)
      		{
      			*outStr = "";
      #ifdef MYSELF
      			string res_string = to_string(_result);
      			string code_string = to_string(_code);
      
      			// 手动序列化
      			*outStr = res_string + SEP + code_string;
      
      			std::cout << "Response Serialize:\n"
                            << *outStr << std::endl;
      #else
      			Json::Value root;
      			root["result"] = _result;
      			root["code"] = _code;
      
      			// Json::FastWriter writer;
      			Json::StyledWriter writer;
      			*outStr = writer.write(root);
      #endif
      			return true;
      		}
      
      		bool Deserialize(const string& inStr)
      		{
      #ifdef MYSELF
      			// 将inStr分隔到数组里面 -> [0]=>10 [1]=>+ [2]=>20
      			vector<string> result;
      			Util::StringSplit(inStr, SEP, &result);
      			if(result.size() != 2)
      				return false;
      			
      			_result = Util::toInt(result[0]);
      			_code = Util::toInt(result[1]);
      #else
      			Json::Value root;
      			Json::Reader reader;
      			reader.parse(inStr, root);
      			_result = root["result"].asInt();
      			_code = root["code"].asInt();
      #endif
      			Print();
      			return true;
      		}
      
      		void Print()
              {
                  std::cout << "_result: " << _result << std::endl;
                  std::cout << "_code: " << _code << std::endl;
              }
      
      	public:
      		int _result;
      		int _code;
      	};
      }
      

      💕

      #include "Sock.hpp"
      #include "Protocol.hpp"
      
      #include <iostream>
      #include <string>
      
      using namespace std;
      using namespace protocol_ns;
      
      static void usage(std::string proc)
      {
          std::cout << "Usage:\n\t" << proc << " serverip serverport\n"
                    << std::endl;
      }
      
      enum
      {
          LEFT,
          OPER,
          RIGHT
      };
      
      
      Request ParseLine(const std::string &line)
      {
          std::string left, right;
          char op;
          int status = LEFT;
      
          int i = 0;
          while(i < line.size())
          {
              switch (status)
              {
              case LEFT:
                  if (isdigit(line[i]))
                      left.push_back(line[i++]);
                  else
                      status = OPER;
                  break;
              case OPER:
                  op = line[i++];
                  status = RIGHT;
                  break;
              case RIGHT:
                  if (isdigit(line[i]))
                      right.push_back(line[i++]);
                  break;
              }
          }
      
          Request req;
          req._x = std::stoi(left);
          req._y = std::stoi(right);
          req._op = op;
      
          return req;
      }
      
      int main(int argc, char* argv[])
      {
      	if(argc != 3)
      	{
      		usage(argv[0]);
      		exit(USAGE_ERR);
      	}
      
      	string serverip = argv[1];
      	uint16_t serverport = atoi(argv[2]);
      
      	Sock sock;
      	sock.Socket();
      
      	int n = sock.Connect(serverip, serverport);
      	if(n != 0) return 1;
      
      	string buffer;
      	while(true)
      	{
      		cout << "Enter# ";
      		string line;
      		getline(cin, line);
      
      		Request req = ParseLine(line);
      		cout << "test:" << req._x << req._op << req._y << endl;
      
      		// 序列化
      		string sendString;
      		req.Serialize(&sendString);
      
      		// 添加报头
      		sendString = AddHeader(sendString);
      
      		// send
      		send(sock.Fd(), sendString.c_str(), sendString.size(), 0);
      
      		// 获取响应
      		string package;
      		int n = 0;
      	START:
      		n = ReadPackage(sock.Fd(), buffer, &package);
      		if(n == 0)
      			goto START;
      		else if(n < 0)
      			break;
      		else
      		{}
      
      		// 去掉报头
      		package = RemoveHeader(package, n);
      
      		// 反序列化
      		Response resp;
      		resp.Deserialize(package);
      
      		cout << "result: " << resp._result << "[code: " << resp._code << "]" << endl;
      	}
      
      	sock.Close();
      	return 0;
      }
      

      💕 TcpServer.hpp

      #pragma once
      #include <iostream>
      #include <functional>
      #include <cstring>
      #include <pthread.h>
      #include "Sock.hpp"
      #include "Protocol.hpp"
      
      using namespace std;
      
      namespace tcpserver_ns
      {
      	using namespace protocol_ns;
      	using func_t = function<Response(const Request&)>;
      	
      	class TcpServer;
      	class ThreadData
      	{
      	public:
      		ThreadData(int sock, string ip, uint16_t port, TcpServer* tsvrp)
      			:_sock(sock), _ip(ip), _port(port), _tsvrp(tsvrp)
      		{}
      		~ThreadData()
      		{}
      	public:
      		int _sock;
      		string _ip;
      		uint16_t _port;
      		TcpServer *_tsvrp;
      	};
      
      	class TcpServer
      	{
      	public:
      		TcpServer(func_t func, uint16_t port)
      		:_func(func), _port(port)
      		{}
      
      		// 初始化服务器
      		void InitServer()
      		{
      			_listensock.Socket();
      			_listensock.Bind(_port);
      			_listensock.Listen();
      			logMessage(Info, "init server done, listensock: %d, errstring: %s", errno, strerror(errno));
      		}
      
      		// 运行服务器
      		void Start()
      		{
      			while(true)
      			{
      				string clientip;
      				uint16_t clientport;
      
      				int sock = _listensock.Accept(&clientip, &clientport);
      				if(sock < 0) continue;
      				logMessage(Debug, "get a new client, client info : [%s:%d]", clientip.c_str(), clientport);
      
      				pthread_t tid; // 创建多线程
      				ThreadData *td = new ThreadData(sock, clientip, clientport, this);
      				pthread_create(&tid, nullptr, ThreadRoutine, td);
      			}
      		}
      
      		static void* ThreadRoutine(void* args)
      		{
      			pthread_detach(pthread_self());
      			ThreadData *td = static_cast<ThreadData *>(args);
      
      			td->_tsvrp->ServiceIO(td->_sock, td->_ip, td->_port);
      			logMessage(Debug, "thread quit, client quit ...");
      			delete td;
      			return nullptr;
      		}
      
      		// 服务器对客户端的数据进行IO处理
      		void ServiceIO(int sock, const std::string &ip, const uint16_t &port)
      		{
      			string inbuffer;
      			while(true)
      			{
      				// 保证自己读到一个完整的字符串报文 "7"\r\n""10 + 20"\r\n
      				string package;
      				int n = ReadPackage(sock, inbuffer, &package);
      				if(n == -1)
      					break;
      				else if(n == 0)
      					continue;
      				else
      				{
      					// 已经得到了一个"7"\r\n""10 + 20"\r\n
      					// 1. 提取有效载荷
      					package = RemoveHeader(package, n);
      
      					// 2. 已经读到了一个完整的string
      					Request req;
      					req.Deserialize(package);
      
      					// 3. 直接提取用户的请求数据
      					Response resp = _func(req); // 业务逻辑
      					
      					// 4. 给用户返回响应——序列化
      					string send_string;
      					resp.Serialize(&send_string);
      
      					// 5. 添加报头
      					send_string = AddHeader(send_string);
      
      					// 6. 发送
      					send(sock, send_string.c_str(), send_string.size(), 0);
      				}
      			}
      			close(sock);
      		}
      
      		~TcpServer()
      		{}
      	private:
      		uint16_t _port; // 端口号
      		Sock _listensock; // 监听套接字
      		func_t _func;
      	};
      }
      

      💕

      #include "TcpServer.hpp"
      #include <memory>
      using namespace tcpserver_ns;
      
      Response calculate(const Request &req)
      {
          // 走到这里,一定保证req是有具体数据的!
      
          Response resp(0, 0);
          switch (req._op)
          {
          case '+':
              resp._result = req._x + req._y;
              break;
          case '-':
              resp._result = req._x - req._y;
              break;
          case '*':
              resp._result = req._x * req._y;
              break;
          case '/':
              if (req._y == 0)
                  resp._code = 1;
              else
                  resp._result = req._x / req._y;
              break;
          case '%':
              if (req._y == 0)
                  resp._code = 2;
              else
                  resp._result = req._x % req._y;
              break;
          default:
              resp._code = 3;
              break;
          }
      
          return resp;
      }
      
      int main()
      {
      	uint16_t port = 8080;
      	unique_ptr<TcpServer> tsvr(new TcpServer(calculate, port));
      	tsvr->InitServer();
      	tsvr->Start();
      	return 0;
      }
      

      💕 Util.hpp

      #pragma once
      #include <iostream>
      #include <string>
      #include <vector>
      #include <cstdlib>
      
      using namespace std;
      
      class Util
      {
      public:
      	static bool StringSplit(const string&str, const string& sep, vector<string>* result)
      	{
      		size_t start = 0;
      		while(start < str.size())
      		{
      			auto pos = str.find(sep, start);
      			if(pos == string::npos) break;
      			result->push_back(str.substr(start, pos - start));
      			start = pos + sep.size();
      		}
      
      		if(start < str.size())
      			result->push_back(str.substr(start));
      		return true;
      	}
      
      	static int toInt(const string& s)
      	{
      		return atoi(s.c_str());
      	}
      };
      

      💕 效果演示

      【网络编程】序列化与反序列化

      整体源码


      版权声明:本文内容来自第三方投稿或授权转载,原文地址:https://chenjiale.blog.csdn.net/article/details/133818920,作者:星河万里᭄ꦿ࿐,版权归原作者所有。本网站转在其作品的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如因作品内容、版权等问题需要同本网站联系,请发邮件至ctyunbbs@chinatelecom.cn沟通。

      上一篇:Java8 特性(二)时间处理

      下一篇:go-Expect-实验

      相关文章

      2025-05-19 09:04:53

      查看RISC-V版本的gcc中默认定义的宏

      查看RISC-V版本的gcc中默认定义的宏

      2025-05-19 09:04:53
      c++ , linux
      2025-05-14 09:51:21

      Docker大学生看了都会系列(十、Docker网络)

      docker使用Linux桥接网卡,在宿主机虚拟一个docker容器网桥(docker0),docker启动一个容器时会根据docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网络网关。

      2025-05-14 09:51:21
      docker , Docker , 容器 , 宿主机 , 模式 , 网桥 , 网络
      2025-05-06 09:19:39

      【30天玩转python】网络编程基础

      网络编程是指编写能够在网络上进行通信的程序,通过网络进行数据的发送与接收。Python 提供了许多库和工具来进行网络编程,如 socket、urllib 和 requests。

      2025-05-06 09:19:39
      TCP , 地址 , 端口 , 编程 , 网络
      2025-05-06 09:18:49

      【Linux 从基础到进阶】Docker 网络配置与调优

      Docker 提供了强大的网络功能,使得容器之间、容器与宿主机、容器与外部网络之间的通信变得高效而灵活。理解和优化 Docker 网络配置对于确保容器应用的性能和可靠性至关重要。

      2025-05-06 09:18:49
      Docker , 容器 , 宿主机 , 网络
      2025-04-01 10:28:37

      小课2:筛选信息命令

      小课2:筛选信息命令

      2025-04-01 10:28:37
      bash , linux , 升序 , 服务器 , 运维
      2025-03-28 07:42:20

      知识图谱的演化:从语义网络到智能决策的关键

      知识图谱的演化:从语义网络到智能决策的关键

      2025-03-28 07:42:20
      图谱 , 数据 , 知识 , 网络 , 语义
      2025-03-27 09:41:50

      初识aurora

      初识aurora

      2025-03-27 09:41:50
      其他 , 笔记 , 网络
      2025-03-26 09:31:12

      shell脚本实现查询代码中定义了多少宏的方法

      shell脚本实现查询代码中定义了多少宏的方法

      2025-03-26 09:31:12
      bash , linux , 运维
      2025-03-26 09:05:38

      Docker网络模型深度解析

      Docker 的网络模型是 Docker 容器之间以及与宿主机之间进行通信的基础。Docker 提供了几种不同的网络模式,包括 bridge(桥接模式,默认模式)、host(主机模式)、none(无网络模式)、container(容器模式)以及自定义网络(如 overlay 网络,用于 Docker Swarm)。这里,我们将详细解析 bridge 网络模式,并提供一个实际的代码示例,展示如何创建容器并让它们在同一桥接网络上通信。

      2025-03-26 09:05:38
      Docker , 创建 , 容器 , 网络
      2025-03-21 06:57:11

      课程介绍,基础—环境安装、判断、循环语句等(爬虫及数据可视化)

      课程介绍,基础—环境安装、判断、循环语句等(爬虫及数据可视化)

      2025-03-21 06:57:11
      python , 关键字 , 可视化 , 爬虫 , 网络 , 语句 , 运算符
      查看更多
      推荐标签

      作者介绍

      天翼云小翼
      天翼云用户

      文章

      33561

      阅读量

      5228841

      查看更多

      最新文章

      【30天玩转python】网络编程基础

      2025-05-06 09:19:39

      初识aurora

      2025-03-27 09:41:50

      shell脚本实现查询代码中定义了多少宏的方法

      2025-03-26 09:31:12

      【附源码】如何用C语言做一个刷弹幕的工具?

      2025-03-06 09:16:11

      【Python】使用numpy库实现Tic-Tac-Toe井字棋

      2025-03-05 09:24:43

      【linux】linux C 程序 注册信号处理函数

      2025-02-10 08:53:59

      查看更多

      热门文章

      程序员之路:Linux压缩命令

      2023-03-21 02:52:11

      Linux下查看进程线程数的方法

      2023-05-15 10:04:01

      Python编程:paramiko模块远程登录

      2023-02-21 08:02:44

      基于jenkins和jmeter实现接口自动化过程

      2023-06-08 06:18:44

      简单的内核编译安装图解

      2023-03-16 07:49:58

      linux网络编程初步

      2023-05-10 06:17:58

      查看更多

      热门标签

      java Java python 编程开发 代码 开发语言 算法 线程 Python html 数组 C++ 元素 javascript c++
      查看更多

      相关产品

      弹性云主机

      随时自助获取、弹性伸缩的云服务器资源

      天翼云电脑(公众版)

      便捷、安全、高效的云电脑服务

      对象存储

      高品质、低成本的云上存储服务

      云硬盘

      为云上计算资源提供持久性块存储

      查看更多

      随机文章

      2023网络爬虫 -- 获取动态加载数据

      Python编程:sublime打开中文文本乱码

      ElasticSearch之cat aliases API

      线程--线程的概念

      linux clamav杀毒软件的安装

      C++快速笔记 1.初识C++

      • 7*24小时售后
      • 无忧退款
      • 免费备案
      • 专家服务
      售前咨询热线
      400-810-9889转1
      关注天翼云
      • 旗舰店
      • 天翼云APP
      • 天翼云微信公众号
      服务与支持
      • 备案中心
      • 售前咨询
      • 智能客服
      • 自助服务
      • 工单管理
      • 客户公告
      • 涉诈举报
      账户管理
      • 管理中心
      • 订单管理
      • 余额管理
      • 发票管理
      • 充值汇款
      • 续费管理
      快速入口
      • 天翼云旗舰店
      • 文档中心
      • 最新活动
      • 免费试用
      • 信任中心
      • 天翼云学堂
      云网生态
      • 甄选商城
      • 渠道合作
      • 云市场合作
      了解天翼云
      • 关于天翼云
      • 天翼云APP
      • 服务案例
      • 新闻资讯
      • 联系我们
      热门产品
      • 云电脑
      • 弹性云主机
      • 云电脑政企版
      • 天翼云手机
      • 云数据库
      • 对象存储
      • 云硬盘
      • Web应用防火墙
      • 服务器安全卫士
      • CDN加速
      热门推荐
      • 云服务备份
      • 边缘安全加速平台
      • 全站加速
      • 安全加速
      • 云服务器
      • 云主机
      • 智能边缘云
      • 应用编排服务
      • 微服务引擎
      • 共享流量包
      更多推荐
      • web应用防火墙
      • 密钥管理
      • 等保咨询
      • 安全专区
      • 应用运维管理
      • 云日志服务
      • 文档数据库服务
      • 云搜索服务
      • 数据湖探索
      • 数据仓库服务
      友情链接
      • 中国电信集团
      • 189邮箱
      • 天翼企业云盘
      • 天翼云盘
      ©2025 天翼云科技有限公司版权所有 增值电信业务经营许可证A2.B1.B2-20090001
      公司地址:北京市东城区青龙胡同甲1号、3号2幢2层205-32室
      • 用户协议
      • 隐私政策
      • 个人信息保护
      • 法律声明
      备案 京公网安备11010802043424号 京ICP备 2021034386号