当前位置: 首页 > news >正文

wordpress企业网站源码深圳英文网站开发公司

wordpress企业网站源码,深圳英文网站开发公司,在线页面设计工具,牛肉煲的做法目录 一#xff0c;关于“协议” 1.1 结构化数据 1.2 序列化和反序列化 二#xff0c;网络版计算器实现准备 2.1 套用旧头文件 2.2 封装sock API 三#xff0c;自定义协议 3.1 关于自定义协议 3.2 实现序列化和反序列化 3.3 测试 三#xff0c;服务器实现 3.1…目录 一关于“协议” 1.1 结构化数据 1.2 序列化和反序列化 二网络版计算器实现准备 2.1 套用旧头文件 2.2 封装sock API 三自定义协议 3.1 关于自定义协议 3.2  实现序列化和反序列化 3.3 测试 三服务器实现 3.1 逻辑梳理 3.2 各头文件实现 四客户端实现 一关于“协议” 1.1 结构化数据 两个主机通过网络和协议进行通信时发送的数据有两种形式 如果传输的数据直接就是一个字符串那么把这个字符串发出去对方也能得到这个字符串如果需要传输的是一个struct结构体那么不能将结构体数据一个个发送到网络中 比如我要实现一个网络版的计算器那么客户端给服务器发送的数据就要包含左操作数运算符和右操作数那么这就不仅仅是一个字符串了而是一组数据 所以客户端不能把这些数据一个个发送过去需要把这些数据“打个包”统一发到网络中此时服务器就能获取到一个完整的数据请求“打包”方式有两种 方案一将结构化的数据结合成一个大的字符串 比如我要发送“11”用户输入的是“整型”“字符”“整型”我们先用to_string函数把整型转为字符串然后用strcat或者C/string的 运算符重载将这三个字符拼接成一个长字符串然后就可以直接发送最后服务器收到了长字符串再以相同的方式进行拆分用stoi函数将字符串转整型就可以提取这些结构化的数据 方案二定制结构化数据实现序列化和反序列化  客户端可以定制一个结构体将需要交互的信息放到结构体种客户端发送前将结构体的数据进行序列化服务器收到数据后进行反序列化此时服务器就能得到客户端发送过来的结构体下面我们来详细讲讲序列化和反序列化 1.2 序列化和反序列化 序列化是将对象的状态信息转换为可以存储或传输的形式字节序列的过程反序列化就是把序列化的字节序列恢复为对象的过程 OSI七层模型中表示层的作用就是“实现数据格式和网络标准数据格式的转换”。前者数据格式就是指数据再应用层上的格式后者就是指序列化之后可以进行网络传输的数据格式  序列化的目的是为了方便网络数据的发送和接收序列化后数据就全变成了二进制数据此时底层在进行数据传输时看到的统一都是二进制序列我发的是二进制数据所以对方收到的也是二进制数据所以需要进行反序列化将二进制数据转化为上层能够识别的比如字符串整型数据 二网络版计算器实现准备 前置博客计算机网络三 —— 简单Udp网络程序-CSDN博客 计算机网络四 —— 简单Tcp网络程序-CSDN博客 下面我们来全程手搓一个网络版计算器服务并且我们自己实现一个自定义协议主要是为了感受一下协议的实现后面我们就不会再自定义协议了直接用现成的 2.1 套用旧头文件 源代码下载计算机网络/自定义协议——网络版计算器 · 小堃学编程/Linux学习 - 码云 - 开源中国 (gitee.com) 网络版计算器我们要用到的头文件有以下几个 我们先把前面写的头文件套用一下 makefile .PHONY:all all:servercal clientcalFlag#-DMySelf1 Lib-ljsoncpp #这个是后面使用json头文件时要用的servercal:ServerCal.ccg -o $ $^ -stdc11 $(Lib) $(Flag) clientcal:ClientCal.ccg -o $ $^ -stdc11 -g $(Lib) $(Flag).PHONY:clean clean:rm -f clientcal servercal Log.hpp #pragma once#include iostream #include time.h #include stdarg.h #include sys/types.h #include sys/stat.h #include fcntl.h #include unistd.h #include stdlib.h#define SIZE 1024#define Info 0 #define Debug 1 #define Warning 2 #define Error 3 #define Fatal 4#define Screen 1 #define Onefile 2 #define Classfile 3#define LogFile log.txtclass Log { public:Log(){printMethod Screen;path ./log/;}void Enable(int method){printMethod method;}std::string levelToString(int level){switch (level){case Info:return Info;case Debug:return Debug;case Warning:return Warning;case Error:return Error;case Fatal:return Fatal;default:return None;}}void printLog(int level, const std::string logtxt){switch (printMethod){case Screen:std::cout logtxt std::endl;break;case Onefile:printOneFile(LogFile, logtxt);break;case Classfile:printClassFile(level, logtxt);break;default:break;}}void printOneFile(const std::string logname, const std::string logtxt){std::string _logname path logname;int fd open(_logname.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0666); // log.txtif (fd 0)return;write(fd, logtxt.c_str(), logtxt.size());close(fd);}void printClassFile(int level, const std::string logtxt){std::string filename LogFile;filename .;filename levelToString(level); // log.txt.Debug/Warning/FatalprintOneFile(filename, logtxt);}~Log(){}void operator()(int level, const char *format, ...){time_t t time(nullptr);struct tm *ctime localtime(t);char leftbuffer[SIZE];snprintf(leftbuffer, sizeof(leftbuffer), [%s][%d-%d-%d %d:%d:%d], levelToString(level).c_str(),ctime-tm_year 1900, ctime-tm_mon 1, ctime-tm_mday,ctime-tm_hour, ctime-tm_min, ctime-tm_sec);va_list s;va_start(s, format);char rightbuffer[SIZE];vsnprintf(rightbuffer, sizeof(rightbuffer), format, s);va_end(s);// 格式默认部分自定义部分char logtxt[SIZE * 2];snprintf(logtxt, sizeof(logtxt), %s %s, leftbuffer, rightbuffer);// printf(%s, logtxt); // 暂时打印printLog(level, logtxt);}private:int printMethod;std::string path; };Log log; Deamon.hpp #pragma once#include iostream #include cstdlib #include unistd.h #include signal.h #include string #include sys/types.h #include sys/stat.h #include fcntl.hconst std::string nullfile /dev/null;void Daemon(const std::string cwd ) {// 1. 忽略其他异常信号signal(SIGCLD, SIG_IGN);signal(SIGPIPE, SIG_IGN);signal(SIGSTOP, SIG_IGN);// 2. 将自己变成独立的会话if (fork() 0)exit(0);setsid();// 3. 更改当前调用进程的工作目录if (!cwd.empty())chdir(cwd.c_str());// 4. 标准输入标准输出标准错误重定向至/dev/nullint fd open(nullfile.c_str(), O_RDWR);if (fd 0){dup2(fd, 0);dup2(fd, 1);dup2(fd, 2);close(fd);} } 2.2 封装sock API 在Udp和Tcp服务器编写时可以发现在使用sock API以及填装sockaddr结构体时步骤都非常相似所以我们可以把这些相似的步骤都封装起来下面是Socket.hpp的代码 #pragma once #include iostream #include string #include unistd.h #include cstring #include sys/types.h #include sys/stat.h #include sys/socket.h #include arpa/inet.h #include netinet/in.h #include Log.hpp#include cstringenum{SocketErr 2,BindErr,ListenErr, };const int backlog 10;class Sock { public:Sock(){}~Sock(){}public:void Socket() // 创建套接字{_sockfd socket(AF_INET, SOCK_STREAM, 0);if (_sockfd 0){log(Fatal, socket error, %s: %d, strerror(errno), errno);exit(SocketErr);}}void Bind(uint16_t port) // 绑定套接字{struct sockaddr_in local;memset(local, 0, sizeof(local));local.sin_family AF_INET;local.sin_port htons(port);local.sin_addr.s_addr INADDR_ANY;if (bind(_sockfd, (struct sockaddr *)local, sizeof(local)) 0) // 如果小于0就绑定失败{log(Fatal, bind error, %s: %d, strerror(errno), errno);exit(BindErr);}}void Listen() // 监听套接字{if (listen(_sockfd, backlog) 0) // 如果小于0就代表监听失败{log(Fatal, listen error, %s: %d, strerror(errno), errno);exit(ListenErr);}}int Accept(std::string *clientip, uint16_t *clientport) // 获取连接参数做输出型参数{struct sockaddr_in peer;socklen_t len sizeof(peer);int newfd accept(_sockfd, (struct sockaddr *)(peer), len);if (newfd 0) // 获取失败{log(Warning, accept error, %s: %d, strerror(errno), errno);return -1;}char ipstr[64];inet_ntop(AF_INET, peer.sin_addr, ipstr, sizeof(ipstr)); // 把网络字节序列转化为字符串保存在ipstr数组里供用户读取*clientip ipstr;*clientport ntohs(peer.sin_port);return newfd;}bool Connect(const std::string ip, const uint16_t port){struct sockaddr_in peer;memset(peer, 0, sizeof(peer));peer.sin_family AF_INET;peer.sin_port htons(port);inet_pton(AF_INET, ip.c_str(), (peer.sin_addr));int n connect(_sockfd, (struct sockaddr *)peer, sizeof(peer));if (n -1){std::cerr connect to ip : port error std::endl;return false;}return true;}void Close(){close(_sockfd);}int Fd(){return _sockfd;}private:int _sockfd; }; 三自定义协议 3.1 关于自定义协议 在之前的文章中介绍过任何的网络协议都要提供两种功能下面是博客的截图计算机网络一 —— 网络基础入门_计算机网络基础教程-CSDN博客 网络版计算器用户会在命令行输入三个字符11然后我们可以拼接成一个长字符串1 1数字与运算符通过一个空格隔开 但是如果客户端连续发了两个字符串那么最终服务器收到的报文就是“1 12 1”可以发现两个字符串粘在了一起所以我们的自定义协议不仅仅要提供将报文和有效载荷分离的能力也要提供将报文与报文分开的能力有下面两种方法 方案一用特殊字符隔开报文与报文 -- 1 1 \n 2 2方案二在报文前面加上报文的长度也就是报头 -- 9\n100 200\n这样就为一个完整的报文其实只要有长度就可以了这里增加\n是为了可读性也是为了方便后面打印 所以下面来梳理一下我们自定义协议的序列化和反序列化全流程 3.2  实现序列化和反序列化 这个部分就是具体实现Protocol.hpp头文件了这个文件具体包含下面几个内容 100200 -- 100 200100 200 -- 9\n100 200 9\n100 200 -- 100 200100 200 -- 100200 该文件包含两个类一个类是请求类是客户端发给服务器用到的类另一个类是响应类是服务器处理完后返回给客户端的类此外还包括两个方法分别是封装报头和将报头和有效载荷分离 Request类 #pragma once #include iostream #include string #include jsoncpp/json/json.h#define MySelf 0 // 去掉注释就是用我们自己的序列化和反序列化加上注释就是用json库提供的const std::string blank_space ; // 分隔符 const std::string protocol_sep \n;class Request // 计算的请求 { public:Request(int data1, int data2, char oper): x(data1), y(data2), op(oper){}Request(){}~Request(){}public:bool Serialize(std::string *out) // 序列化{ #ifdef MySelf// 1构建报文的有效载荷// 需要把结构化的数据转化为字符串 struct -- string, x op ystd::string s std::to_string(x);s blank_space;s op;s blank_space;s std::to_string(y);// 走到这里的时候就是字符串 x op y// 但是在传输的时候可能发过来的不是完整的一个报文10 20而是只有半个报文10 // 解决方案一用特殊字符隔开报文与报文 -- 10 20 \n 20 40// 解决方案二再在报文前面加一个字符串的长度也就是报头例如s.size()// 结合起来就是9\n100 200\n为一个完整的报文其实只要有长度就可以了这里增加\n是为了可读性也是为了方便后面// 2封装报头*out s;return true; #elseJson::Value root;root[x] x;root[y] y;root[op] op;Json::FastWriter w;*out w.write(root);return true;#endif}bool DeSerialize(const std::string in) // 反序列化 9\n10 20{ #ifdef MySelfstd::size_t left in.find(blank_space); // 找空格的左边10 20也就是找10的右边位置if (left std::string::npos) // 没找到空格说明当前解析错误{return false;}std::string part_x in.substr(0, left); // 截取第一个数字也就是10std::size_t right in.rfind(blank_space); // 逆向再次找空格10 20找20左边的位置if (right std::string::npos) // 没找到空格说明当前解析错误{return false;}std::string part_y in.substr(right 1); // 截取后面的数字也就是201是因为找到的是空格的右边1跳过空格才是数字if (left 2 ! right)return false; // 数字中间还有运算符所以left2就应该是right的左边那个空格的左边位置如果不是那么就是解析错误op in[left 1]; // 拿到运算符// op in[right - 1]; //一样的x std::stoi(part_x); // 拿到数字y std::stoi(part_y);return true; #elseJson::Value root;Json::Reader r;r.parse(in, root);x root[x].asInt();y root[y].asInt();op root[op].asInt();return true; #endif}void DebugPrint(){std::cout 新请求构建完成: x op y ? std::endl;}public:int x;int y;char op; // 运算符 };class Response // 计算的应答 { public:Response(int res, int c): result(res), code(c){}Response(){}~Response(){}public:bool Serialize(std::string *out) // 序列化{ #ifdef MySelf// 1构建报文的有效载荷//len\nresult codestd::string s std::to_string(result);s blank_space;s std::to_string(code);*out s;return true; #elseJson::Value root;root[result] result;root[code] code;// Json::FastWriter w;Json::StyledWriter w;*out w.write(root);return true; #endif}bool DeSerialize(const std::string in) // 反序列化{ #ifdef MySelf// 对服务器发过来的结果报文做解析: result codestd::size_t pos in.find(blank_space); // 找空格的左边if (pos std::string::npos) // 没找到空格说明当前解析错误{return false;}std::string part_left in.substr(0, pos); // 截取第一个数字也就是resultstd::string part_right in.substr(pos 1); // 截取后面第二个数字也就是coderesult std::stoi(part_left);code std::stoi(part_right);return true; #elseJson::Value root;Json::Reader r;r.parse(in, root);result root[result].asInt();code root[code].asInt();return true; #endif}void DebugPrint(){std::cout 结果响应完成, result: result , code: code std::endl;}public:int result; // x op yint code; // 错误码为0时结果正确为其它数时对应的数表示对应的原因 }; Response类 class Response // 计算的应答 { public:Response(int res, int c): result(res), code(c){}Response(){}~Response(){}public:bool Serialize(std::string *out) // 序列化{ #ifdef MySelf// 1构建报文的有效载荷//len\nresult codestd::string s std::to_string(result);s blank_space;s std::to_string(code);*out s;return true; #elseJson::Value root;root[result] result;root[code] code;// Json::FastWriter w;Json::StyledWriter w;*out w.write(root);return true; #endif}bool DeSerialize(const std::string in) // 反序列化{ #ifdef MySelf// 对服务器发过来的结果报文做解析: result codestd::size_t pos in.find(blank_space); // 找空格的左边if (pos std::string::npos) // 没找到空格说明当前解析错误{return false;}std::string part_left in.substr(0, pos); // 截取第一个数字也就是resultstd::string part_right in.substr(pos 1); // 截取后面第二个数字也就是coderesult std::stoi(part_left);code std::stoi(part_right);return true; #elseJson::Value root;Json::Reader r;r.parse(in, root);result root[result].asInt();code root[code].asInt();return true; #endif}void DebugPrint(){std::cout 结果响应完成, result: result , code: code std::endl;}public:int result; // x op yint code; // 错误码为0时结果正确为其它数时对应的数表示对应的原因 }; 添加和去掉报头函数 std::string Encode(const std::string content) // 添加报头 {std::string packge std::to_string(content.size()); // 加报头packge protocol_sep; // 加\npackge content; // 加正文packge protocol_sep; // 再加\nreturn packge; }bool Decode(std::string package, std::string *content) // 解析并去掉报头 9\n10 20\n --10 20 俗称解包但是只是去掉了报头没有做报文的具体解析 {std::size_t pos package.find(protocol_sep); // 找到\n的左边if (pos std::string::npos)return false; // 解析失败std::string len_str package.substr(0, pos); // 从开始截到我找到的\n处把前面的9给截出来std::size_t len std::stoi(len_str); // 把截出来的报头转化为size_t也就是把字符串9转化成数字9// packge的长度 报头长度len_str 有效载荷长度content_str 两个\n 2std::size_t total_len len_str.size() len 2;// ①找到了第一个\n说明一定有长度如果没找到\n就说明连报头都没有// ②有了长度报头你也还得保证后面的内容也是完整的如果不完整也就是长度不一样那我也就不玩了if (package.size() total_len)return false;// 走到这一步说明我们能保证报文是完整的开始拿有效载荷*content package.substr(pos 1, len); // pos现在是第一个\n左边的位置1后面的就是正文内容正文内容长度为len// 移除一个报文该功能需要和网络相结合package.erase(0, total_len);return true; } 3.3 测试 我们可以在ServerCal.cc文件里测试上面我们的序列化和反序列化操作 先测试Request ServerCal.cc #include Log.hpp #include Socket.hpp #include TcpServer.hpp #include Protocol.hpp #include ServerCal.hpp #include Deamon.hppint main() {// Request测试--------------------Request req(10, 20, );std::string s;req.Serialize(s);std::cout 有效载荷为: s std::endl;s Encode(s);std::cout 报文为 s;std::string content;bool r Decode(s, content); //分离报头和有效载荷std::cout 分离报头后的有效载荷为: content std::endl;Request temp;temp.DeSerialize(content); //解析有效载荷std::cout 有效载荷分离后, x为: temp.x 运算符为:\ temp.op \ y为: temp.y std::endl;return 0; } 然后是Response的测试  ServerCal.cc #include Log.hpp #include Socket.hpp #include TcpServer.hpp #include Protocol.hpp #include ServerCal.hpp #include Deamon.hppint main() {// Response测试--------------------Response resp(10, 20);std::string s;resp.Serialize(s);std::cout 有效载荷为: s std::endl;std::string package Encode(s); //分离报头和有效载荷std::cout 报文为: package;s ;bool r Decode(package, s);std::cout 分离报头后的有效载荷为: s std::endl;Response temp;temp.DeSerialize(s); // 解析有效载荷std::cout 解析有效载荷: std::endl;std::cout 结果为: temp.result std::endl;std::cout 错误码为: temp.code std::endl;return 0; } 三服务器实现 3.1 逻辑梳理 服务器涉及两个个头文件和一个源文件有点绕下面先梳理一下 有三个文件 首先TcpServer.hpp是服务器主函数ServerCal.cc包含服务器初始化和启动的main函数ServerCal.hpp是进行计算器运算的头文件首先构建服务器对象并在构造函数里将ServerCal.cc里面的运算函数带进去然后是初始化服务器执行创建套接字等操作然后启动服务器当服务器收到客户端发来的报文后直接将报文传给运算函数由运算函数做去掉报头解析有效载荷等过程并执行运算最后把运算结果再次构建成响应报文以返回值形式返回给服务器运行函数然后服务器再把响应报文发给客户端完成一次计算请求处理 3.2 各头文件实现 Server.hpp实现 #pragma once #include iostream #include string #include Protocol.hppenum {Div_Zero 1,Mod_Zero,Other_Oper };class ServerCal { public:ServerCal(){}~ServerCal(){}Response CalculatorHelper(const Request 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 Div_Zero;}else{resp.result req.x / req.y;}}break;case %:{if (req.y 0){resp.code Mod_Zero;}else{resp.result req.x % req.y;}}break;default:resp.code Other_Oper;break;}return resp;}std::string Calculator(std::string package){std::string content;if (!Decode(package, content)) // 分离报头和有效载荷len\n10 20\nreturn ;// 走到这里就是完整的报文Request req;if (!req.DeSerialize(content)) // 反序列化解析有效载荷 10 20 -- x10 op y20return ;content ;Response resp CalculatorHelper(req); // 执行计算逻辑resp.Serialize(content); // 序列化计算结果的有效载荷 result10, code0content Encode(content); // 将有效载荷和报头封装成响应报文 len\n30 0return content;} }; TcpServer.hpp实现 #pragma once #include Log.hpp #include Socket.hpp #include signal.h #include string #include functionalusing func_t std::functionstd::string(std::string package);class TcpServer { public:TcpServer(uint16_t port, func_t callback): _port(port), _callback(callback){}bool InitServer(){// 创建绑定监听套接字_listensockfd.Socket();_listensockfd.Bind(_port);_listensockfd.Listen();log(Info, Init server... done);return true;}void Start(){signal(SIGCHLD, SIG_IGN); // 忽略signal(SIGPIPE, SIG_IGN);while (true){std::string clientip;uint16_t clientport;int sockfd _listensockfd.Accept(clientip, clientport);if (sockfd 0)continue;log(Info, accept a new link, sockfd: %d, clientip: %s, clientport: %d, sockfd, clientip.c_str(), clientport);// 走到了这里就是成功获取发起连接方IP与port后面就是开始提供服务if (fork() 0){_listensockfd.Close();// 进行数据运算服务std::string inbuffer_stream;while (true){char buffer[1280];ssize_t n read(sockfd, buffer, sizeof(buffer));if (n 0){buffer[n] 0;inbuffer_stream buffer; // 这里用log(Debug, debug:\n%s, inbuffer_stream.c_str());while (true){std::string info _callback(inbuffer_stream);// if (info.size() 0) //ServerCal.hpp解析报文失败的话会返回空串if (info.empty()) // 空的话代表inbuffstream解析时出问题表示不遵守协议发不合法的报文给我我直接丢掉不玩了break; // 不能用continuelog(Debug, debug, response:\n%s, info.c_str());log(Debug, debug:\n%s, inbuffer_stream.c_str());write(sockfd, info.c_str(), info.size());}}else if (n 0) // 读取出错break;else // 读取出错break;}exit(0);}close(sockfd);}}~TcpServer(){}private:uint16_t _port;Sock _listensockfd;func_t _callback; }; ServerCal.cc实现 #include Log.hpp #include Socket.hpp #include TcpServer.hpp #include Protocol.hpp #include ServerCal.hpp #include Deamon.hppstatic void Usage(const std::string proc) {std::cout \nUsage: proc port\n\n std::endl; }int main(int argc, char *argv[]) {if (argc ! 2){Usage(argv[0]);exit(0);}uint16_t port std::stoi(argv[1]);ServerCal cal;TcpServer *tsvp new TcpServer(port, std::bind(ServerCal::Calculator, cal, std::placeholders::_1));tsvp-InitServer();//Daemon();//daemon(0, 0);tsvp-Start();// Request测试--------------------// Request req(10, 20, );// std::string s;// req.Serialize(s);// std::cout 有效载荷为: s std::endl;// s Encode(s);// std::cout 报文为 s;// std::string content;// bool r Decode(s, content); //分离报头和有效载荷// std::cout 分离报头后的有效载荷为: content std::endl;// Request temp;// temp.DeSerialize(content); //解析有效载荷// std::cout 有效载荷分离后, x为: temp.x 运算符为:\ temp.op \ y为: temp.y std::endl;// Response测试--------------------// Response resp(10, 20);// std::string s;// resp.Serialize(s);// std::cout 有效载荷为: s std::endl;// std::string package Encode(s); //分离报头和有效载荷// std::cout 报文为: package;// s ;// bool r Decode(package, s);// std::cout 分离报头后的有效载荷为: s std::endl;// Response temp;// temp.DeSerialize(s); // 解析有效载荷// std::cout 解析有效载荷: std::endl;// std::cout 结果为: temp.result std::endl;// std::cout 错误码为: temp.code std::endl;return 0; } 四客户端实现 客户端的话为了方便发送计算请求会采用随机数的方式获取运算数和运算符如下代码 #include iostream #include string #include ctime #include cassert #include unistd.h #include Socket.hpp #include Protocol.hppstatic void Usage(const std::string proc) {std::cout \nUsage: proc serverip serverport\n std::endl; }int main(int argc, char *argv[]) {if (argc ! 3){Usage(argv[0]);exit(0);}std::string serverip argv[1];uint16_t serverport std::stoi(argv[2]); //获取IP和端口Sock sockfd;sockfd.Socket();if (!sockfd.Connect(serverip, serverport))return 1;srand(time(nullptr) ^ getpid()); // 种随机数种子int cnt 1;const std::string opers -*/%-^;std::string inbuffer_stream;while (cnt 5){std::cout 第 cnt 次测试....., std::endl;int x rand() % 100 1;usleep(1234);int y rand() % 100;usleep(4321);char oper opers[rand() % opers.size()];Request req(x, y, oper);req.DebugPrint();// 下面是根据协议发送给对方std::string package;req.Serialize(package); // 序列化package Encode(package); // 形成报文int fd sockfd.Fd(); // 获取套接字write(fd, package.c_str(), package.size()); // 将请求从客户端往服务端写过去// 下面是读取服务器发来的结果并解析char buffer[128];ssize_t n read(sockfd.Fd(), buffer, sizeof(buffer)); // 读取服务器发回来的结果但是这里也无法保证能读取到一个完整的报文if (n 0) // 读成功了{buffer[n] 0;inbuffer_stream buffer; // len\nresult code\nstd::cout inbuffer_stream std::endl;std::string content;bool r Decode(inbuffer_stream, content); // 去掉报头result code\nassert(r); // r为真说明报头成功去掉Response resp;r resp.DeSerialize(content); // 对有效荷载进行反序列化assert(r);resp.DebugPrint(); // 打印结果}std::cout std::endl;sleep(1);cnt;}sockfd.Close();return 0; } 效果演示
http://www.hkea.cn/news/14425364/

相关文章:

  • 姓氏网站建设的意见和建议青岛网站建设及app
  • 服务网站开发手机有办法做网站吗
  • 建网站 网站内容怎么做谷歌浏览器app
  • 网站建设摘要营销推广方式都有哪些
  • 电商网站开发思路模版此网站正在建设中
  • 杭州网站建设|网站设计电子商务网站开发的基本原则
  • 鞋子网站建设策划书关键词排名哪里查
  • asp源代码网站网站建设公司的成本有哪些方面
  • 深圳网站建设 工作室长春seo公司
  • 网站建设项目工作分解加工平台
  • 快速域名网站备案没有注册公司可以建网站吗
  • 字体设计欣赏网站网站开发公司网站模板
  • 天津网站建设展示型网站举例
  • 东莞网站建设建网站龙岩天宫山攻略
  • 网站建设中请稍后再访问做国外的众筹网站
  • 南昌市建设工程质量监督网站软件开发方式
  • 湖南网站建站系统哪家好凡科门店通怎么样
  • 建设网站的心得信阳高端网站建设
  • 网站优化 ppt常州做网站优化
  • 手机站点cn网站加载模式
  • 如何在记事本中做网站链接wordpress主题有后台
  • 企业网站建设毕业设计论文wordpress两个站点共用用户
  • 丽江建设网站怎么做好网络营销推广
  • 微网站建设方案书企业做网站有用吗天涯
  • 长沙企业模板建站北京网站模板建设
  • 呼和浩特市做网站的企业设计师去哪找
  • 个人网站备案下载站wordpress优秀网站
  • 网站开发环境vs2015是什么wordpress超炫模板
  • 网站设计师接单微科技h5制作网站模板下载
  • 浏览器的网站通知怎么做wordpress网站费用