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

桂林龙胜网站建设如何给网站添加搜索关键字

桂林龙胜网站建设,如何给网站添加搜索关键字,公司做网站的费用属于什么费用,邯郸网站建设选哪家前言 作者#xff1a;小蜗牛向前冲 名言#xff1a;我可以接受失败#xff0c;但我不能接受放弃 如果觉的博主的文章还不错的话#xff0c;还请点赞#xff0c;收藏#xff0c;关注#x1f440;支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 目录 一、再谈协议… 前言 作者小蜗牛向前冲 名言我可以接受失败但我不能接受放弃   如果觉的博主的文章还不错的话还请点赞收藏关注支持博主。如果发现有问题的地方欢迎❀大家在评论区指正  目录 一、再谈协议 二、序列化和反序化 1、网络版本计算器的场景搭建 2、服务器构建  3、客户端构建 4、序列化和反序列化  4.1自定义序列化和反序列化 4.2json实现序列化和反序列化 5、测试 本期学习重点理解序化和反序列化 一、再谈协议 在前面博客谈网络的时候我们认为协议就是一种约定在用socket api接口的时候都是按照“字符串”的方式来进行发送和接受的但是如果我们要传输一些结构化的数据又该怎么办 这就要我们将数据序列化进行传输或者接收。 在网络通信中传输结构化数据的常见方法有以下几种 序列化 将结构化数据转换为字符串或字节流进行传输。在发送端可以使用一种序列化格式将数据转换为字符串或字节流在接收端再将接收到的字符串或字节流反序列化为相应的数据结构。常见的序列化格式包括 JSONJavaScript Object Notation、XMLeXtensible Markup Language、Protocol Buffersprotobuf、MessagePack 等。选择序列化格式时需要考虑数据的大小、可读性、解析效率等因素。 数据格式协议 使用一种规定的数据格式协议进行数据传输。这种方法通常需要双方预先约定好数据格式协议并按照协议的规定进行数据的编码和解码。常见的数据格式协议包括 HTTP、FTP、SMTP 等。在 HTTP 协议中可以使用 Content-Type 来指定数据的格式如 application/json 表示 JSON 格式数据application/xml 表示 XML 格式数据。 自定义协议 自定义通信协议定义数据的传输格式和规则。在自定义协议中可以根据实际需求灵活地定义数据的结构和编码方式以及通信过程中的规则和约定。自定义协议通常需要双方进行协商和实现但可以更好地满足特定场景下的需求。 二、序列化和反序化 为了更好的理解下面我们将通过自己定制tcp协议将数据进行序列化和反序列化。为了方便叙述我们简单的制定网络版本的计算 来理解协议中序列化和反序列化。 1、网络版本计算器的场景搭建 我们的构想是客户端通过将计算请求数据序列化,发送到网络中服务端接收后将数据进行反序列化进行计算处理。 处理过程大致如上图 c-s调用函数发送数据的本质就是将一个缓冲区的拷贝到另外一个缓冲区。s-c服务器回显数据的本质也是将s中缓冲区的数据拷贝到c中的缓冲区所以所tcp是全双工的 2、服务器构建  这里构建的服务器和上篇在套接字中的是没有本质区别的 #pragma once#include iostream #include string #include cstring #include cstdlib #include functional #include unistd.h #include sys/types.h #include sys/socket.h #include netinet/in.h #include arpa/inet.h #include sys/wait.h #include signal.h #include log.hpp #include protocol.hpp using namespace std;namespace server {enum{USAGE_ERR 1,SOCKET_ERR,BIND_ERR,LISTEN_ERR};static const uint16_t gport 8080;static const int gbacklog 5;// const Request req: 输入型// Response resp: 输出型typedef std::functionbool(const Request req, Response resp) func_t;// 保证解耦void handlerEntery(int sock, func_t func){std::string inbuffer;while (true){// 1. 读取content_len\r\nx op y\r\n// 1.1 你怎么保证你读到的消息是 【一个】完整的请求std::string req_text, req_str;// 1.2 我们保证我们req_text里面一定是一个完整的请求content_len\r\nx op y\r\nif (!recPackage(sock, inbuffer, req_text))return;std::cout 带报头的请求\n req_text std::endl;if (!deLength(req_text, req_str))return;std::cout 去掉报头的正文\n req_str std::endl;// 2. 对请求Request反序列化// 2.1 得到一个结构化的请求对象Request req;if (!req.deserialize(req_str))return;// 3. 计算机处理req.x, req.op, req.y --- 业务逻辑// 3.1 得到一个结构化的响应Response resp;func(req, resp); // req的处理结果全部放入到了resp 回调是不是不回来了不是// 4.对响应Response进行序列化// 4.1 得到了一个字符串std::string resp_str;resp.serialize(resp_str);std::cout 计算完成, 序列化响应: resp_str std::endl;// 5. 然后我们在发送响应// 5.1 构建成为一个完整的报文std::string send_string enLength(resp_str);send(sock, send_string.c_str(), send_string.size(), 0); // 其实这里的发送也是有问题的不过后面再说}}class CalServer{public:CalServer(const uint16_t port gport) : _listensock(-1), _port(port){}void initServer(){// 1. 创建socket文件套接字对象_listensock socket(AF_INET, SOCK_STREAM, 0);if (_listensock 0){logMessage(FATAL, create socket error);exit(SOCKET_ERR);}logMessage(NORMAL, create socket success: %d, _listensock);// 2. bind绑定自己的网络信息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(_listensock, (struct sockaddr *)local, sizeof(local)) 0){logMessage(FATAL, bind socket error);exit(BIND_ERR);}logMessage(NORMAL, bind socket success);// 3. 设置socket 为监听状态if (listen(_listensock, gbacklog) 0) // 第二个参数backlog后面在填这个坑{logMessage(FATAL, listen socket error);exit(LISTEN_ERR);}logMessage(NORMAL, listen socket success);}void start(func_t func){for (;;){// 4. server 获取新链接// sock, 和client进行通信的fdstruct sockaddr_in peer;socklen_t len sizeof(peer);int sock accept(_listensock, (struct sockaddr *)peer, len);if (sock 0){logMessage(ERROR, accept error, next);continue;}logMessage(NORMAL, accept a new link success, get new sock: %d, sock); // ?// version 2 多进程版(2)pid_t id fork();if (id 0) // child{close(_listensock);// if(fork()0) exit(0);// serviceIO(sock);handlerEntery(sock, func);close(sock);exit(0);}close(sock);// fatherpid_t ret waitpid(id, nullptr, 0);if (ret 0){logMessage(NORMAL, wait child success); // ?}}}~CalServer() {}private:int _listensock; // 不是用来进行数据通信的它是用来监听链接到来获取新链接的uint16_t _port;}; } 对于 handlerEntery这个操作我们要分析在这函数中首先我们要获取到由客户端发送过来的报文而客户端发送过来的报文肯定是经过序列化的所以我们要进行反序列化在通过func回调函数得到一个结构化的响应在将响应通过处理发送给客户端。 // 保证解耦void handlerEntery(int sock, func_t func){std::string inbuffer;while (true){// 1. 读取content_len\r\nx op y\r\n// 1.1 你怎么保证你读到的消息是 【一个】完整的请求std::string req_text, req_str;// 1.2 我们保证我们req_text里面一定是一个完整的请求content_len\r\nx op y\r\nif (!recPackage(sock, inbuffer, req_text))return;std::cout 带报头的请求\n req_text std::endl;if (!deLength(req_text, req_str))return;std::cout 去掉报头的正文\n req_str std::endl;// 2. 对请求Request反序列化// 2.1 得到一个结构化的请求对象Request req;if (!req.deserialize(req_str))return;// 3. 计算机处理req.x, req.op, req.y --- 业务逻辑// 3.1 得到一个结构化的响应Response resp;func(req, resp); // req的处理结果全部放入到了resp 回调是不是不回来了不是// 4.对响应Response进行序列化// 4.1 得到了一个字符串std::string resp_str;resp.serialize(resp_str);std::cout 计算完成, 序列化响应: resp_str std::endl;// 5. 然后我们在发送响应// 5.1 构建成为一个完整的报文std::string send_string enLength(resp_str);send(sock, send_string.c_str(), send_string.size(), 0); // 其实这里的发送也是有问题的不过后面再说}} 对于calServer.cc的主程序就是简单进行cal计算业务  #include calServer.hpp #include memoryusing namespace server; using namespace std;static void Usage(string proc) {cout \nUsage:\n\t proc local_port\n\n; } // req: 里面一定是我们的处理好的一个完整的请求对象 // resp: 根据req进行业务处理填充resp不用管理任何读取和写入序列化和反序列化等任何细节 bool cal(const Request req, Response resp) {// req已经有结构化完成的数据啦你可以直接使用resp._exitcode OK;resp._result OK;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._exitcode DIV_ZERO;elseresp._result req._x / req._y;}break;case %:{if (req._y 0)resp._exitcode MOD_ZERO;elseresp._result req._x % req._y;}break;default:resp._exitcode OP_ERROR;break;}return true; }// tcp服务器启动上和udp server一模一样 // ./tcpserver local_port int main(int argc, char *argv[]) {if (argc ! 2){Usage(argv[0]);exit(USAGE_ERR);}uint16_t port atoi(argv[1]);unique_ptrCalServer tsvr(new CalServer(port));tsvr-initServer();tsvr-start(cal);return 0; } 3、客户端构建 对于客户端calClinet.hpp完成的主要逻辑是进行连网输入计算对服务器进行计算请求在进行计算信息的构建。  #pragma once#include iostream #include string #include cstring #include sys/types.h #include sys/socket.h #include netinet/in.h #include arpa/inet.h #include unistd.h #include protocol.hpp#define NUM 1024 using namespace std; class CalClient { public:CalClient(const std::string serverip, const uint16_t serverport): _sock(-1), _serverip(serverip), _serverport(serverport){}void initClient(){// 1. 创建socket_sock socket(AF_INET, SOCK_STREAM, 0);if (_sock 0){std::cerr socket create error std::endl;exit(2);}// 2. tcp的客户端要不要bind要的 要不要显示的bind不要这里尤其是client port要让OS自定随机指定// 3. 要不要listen不要// 4. 要不要accept? 不要// 5. 要什么呢要发起链接}void start(){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());if (connect(_sock, (struct sockaddr *)server, sizeof(server)) ! 0){std::cerr socket connect error std::endl;}else{std::string line;std::string inbuffer;while (true){std::cout mycal ;// 输入计算getline(cin, line);// 进行请求Request req ParseLine(line);string content; // 存放计算信息req.serialize(content);string send_string enLength(content); // 添加报头send(_sock, send_string.c_str(), send_string.size(), 0);string package, text;if (!recPackage(_sock, inbuffer, package))continue;if (!deLength(package, text))continue;// 响应Response resp;resp.deserialize(text);std::cout exitCode: resp._exitcode std::endl;std::cout result: resp._result std::endl;}}}// 从文本中提取计算格式信息然后用这些信息构建请求Request ParseLine(const std::string line){//11 123*456 12/0int status 0; // 0:操作符之前1:碰到了操作符 2:操作符之后int i 0;int cnt line.size();string left, right;char op;while (i cnt){switch (status){case 0:{if (!isdigit(line[i])) // isdigit检查字符是否是十进制{op line[i];status 1;}elseleft.push_back(line[i]);}break;case 1:{i;status 2;}break;case 2:{right.push_back(line[i]);}break;}}std::cout std::stoi(left) std::stoi(right) op std::endl;return Request(std::stoi(left), std::stoi(right), op);}~CalClient(){if (_sock 0)close(_sock);}private:int _sock;std::string _serverip;uint16_t _serverport; };calClient.cc  #include calClient.hpp #include memoryusing namespace std;static void Usage(string proc) {cout \nUsage:\n\t proc serverip serverport\n\n; } // ./tcpclient serverip serverport int main(int argc, char *argv[]) {if (argc ! 3){Usage(argv[0]);exit(1);}string serverip argv[1];uint16_t serverport atoi(argv[2]);unique_ptrCalClient tcli(new CalClient(serverip, serverport));tcli-initClient();tcli-start();return 0; } 4、序列化和反序列化  4.1自定义序列化和反序列化 前面说了一大堆要对数据进行序列化和反序列化 那到底什么是序列化和反序列其实本质就是将一堆字符串整和成一个字符串。为了完成我们网络计算器这里我们写了二个类一个是 Request对数据进行请求另外一个是Response,每个类中都要对序化和反序列进行设计 class Request { public:Request() : _x(0), _y(0), _op(0){}Request(int x, int y, char op) : _x(x), _y(y), _op(op){}// 1. 自己写// 2. 用现成的bool serialize(std::string *out){}// x op yyyy;bool deserialize(const std::string in){} public:// x op yint _x;int _y;char _op; }; // 响应 class Response { public:Response() : _exitcode(0), _result(0){}Response(int exitcode, int result) : _exitcode(exitcode), _result(result){}bool serialize(std::string *out){}bool deserialize(const std::string in){}public:int _exitcode; // 0计算成功!0表示计算失败具体是多少定好标准int _result; // 计算结果 }; 其中序列化和反序列化可以自己进行编写也可以通过库进行完成。 在大部分场景中我们都是用json进行序列结构的对于自定义序列化每个实现方式可能不同所以不重点分析了下面会有完整代码大家可以参考实现 4.2json实现序列化和反序列化 在Linux上使用json我们要进行库的安装 sudo yum install -y jsoncpp-devel 序列化  使用了 JsonCpp 库来创建一个 JSON 对象 root然后将一些值 _x、_y 和 _op 分别存储到 JSON 对象的键 first、second 和 oper 中。接下来使用 Json::FastWriter 对象 writer 来将 JSON 对象 root 转换为字符串并将结果写入到 out 指向的位置。 Json::Value root;root[first] _x;root[second] _y;root[oper] _op;Json::FastWriter writer;// Json::StyledWriter writer;*out writer.write(root); 反序列化  使用了 JsonCpp 库来解析输入的 JSON 字符串 in并将解析得到的值存储到 Json::Value 类型的对象 root 中。然后通过访问 root 对象的键 first、second 和 oper 来获取相应的值并将这些值转换为整数类型并分别存储到 _x、_y 和 _op 变量中。 Json::Value root;Json::Reader reader;reader.parse(in, root);_x root[first].asInt();_y root[second].asInt();_op root[oper].asInt(); 注意asInt() 函数用于将 JSON 值转换为整数类型 protocol.hpp 完整代码实现添加报文去报头请求响应获取数据包 #pragma once#include iostream #include cstring #include string #include sys/types.h #include sys/socket.h #include jsoncpp/json/json.h#define SEP #define SEP_LEN strlen(SEP) #define LINE_SEP /r/n // /r回车 /n换行 /r/n表示换行的同时将光标移动到行首 #define LINE_SEP_LEN strlen(LINE_SEP) using namespace std;// 错误枚举 enum {OK 0,DIV_ZERO,MOD_ZERO,OP_ERROR }; // x op y - content_len\r\nx op y\r\n // exitcode result - content_len\r\nexitcode result\r\n// 添加报头 string enLength(string text) {string send_string to_string(text.size());send_string LINE_SEP;send_string text;send_string LINE_SEP;return send_string; } // 去报头 // content_len\r\nexitcode result\r\n bool deLength(const std::string package, std::string *text) {auto pos package.find(LINE_SEP);if (pos string::npos)return false;string text_len_string package.substr(0, pos);int text_len stoi(text_len_string);*text package.substr(pos LINE_SEP_LEN, text_len);return true; }// 请求 class Request { public:Request() : _x(0), _y(0), _op(0){}Request(int x, int y, char op) : _x(x), _y(y), _op(op){}// 1. 自己写// 2. 用现成的bool serialize(std::string *out){ #ifdef MYSELF*out ;// 结构化 - x op y;std::string x_string std::to_string(_x);std::string y_string std::to_string(_y);*out x_string;*out SEP;*out _op;*out SEP;*out y_string; #elseJson::Value root;root[first] _x;root[second] _y;root[oper] _op;Json::FastWriter writer;// Json::StyledWriter writer;*out writer.write(root); #endifreturn true;}// x op yyyy;bool deserialize(const std::string in){ #ifdef MYSELF// x op y - 结构化auto left in.find(SEP);auto right in.rfind(SEP);if (left std::string::npos || right std::string::npos)return false;if (left right)return false;if (right - (left SEP_LEN) ! 1)return false;std::string x_string in.substr(0, left); // [0, 2) [start, end) , start, end - startstd::string y_string in.substr(right SEP_LEN);if (x_string.empty())return false;if (y_string.empty())return false;_x std::stoi(x_string);_y std::stoi(y_string);_op in[left SEP_LEN]; #elseJson::Value root;Json::Reader reader;reader.parse(in, root);_x root[first].asInt();_y root[second].asInt();_op root[oper].asInt(); #endifreturn true;}public:// x op yint _x;int _y;char _op; };// 响应 class Response { public:Response() : _exitcode(0), _result(0){}Response(int exitcode, int result) : _exitcode(exitcode), _result(result){}bool serialize(std::string *out){ #ifdef MYSELF*out ;std::string ec_string std::to_string(_exitcode);std::string res_string std::to_string(_result);*out ec_string;*out SEP;*out res_string; #elseJson::Value root;root[exitcode] _exitcode;root[result] _result;Json::FastWriter writer;*out writer.write(root); #endifreturn true;}bool deserialize(const std::string in){ #ifdef MYSELF// exitcode resultauto mid in.find(SEP);if (mid std::string::npos)return false;std::string ec_string in.substr(0, mid);std::string res_string in.substr(mid SEP_LEN);if (ec_string.empty() || res_string.empty())return false;_exitcode std::stoi(ec_string);_result std::stoi(res_string); #elseJson::Value root;Json::Reader reader;reader.parse(in, root);_exitcode root[exitcode].asInt();_result root[result].asInt(); #endifreturn true;}public:int _exitcode; // 0计算成功!0表示计算失败具体是多少定好标准int _result; // 计算结果 };// 获取数据包 // content_len\r\nx op y\r\ncontent_len\r\nx op y\r\ncontent_len\r\nx op bool recPackage(int sock, string inbuffer, string *text) {char buffer[1024];while (true){// 从网络中接受资源ssize_t n recv(sock, buffer, sizeof(buffer) - 1, 0);if (n 0){buffer[n] 0;inbuffer buffer;// 分析auto pos inbuffer.find(LINE_SEP);if (pos string::npos)continue;string text_len_string inbuffer.substr(0, pos);int text_len stoi(text_len_string);// 报文的总长度int total_len text_len_string.size() 2 * LINE_SEP_LEN text_len;// text_len_string \r\n text \r\n inbuffer.size();std::cout 处理前#inbuffer: \n inbuffer std::endl;if (inbuffer.size() total_len){std::cout 你输入的消息没有严格遵守我们的协议正在等待后续的内容, continue std::endl;continue;}// 最少一个完整报文*text inbuffer.substr(0, total_len);inbuffer.erase(0, total_len);std::cout 处理后#inbuffer:\n inbuffer std::endl;break;}elsereturn false;}return true; }5、测试 下面我们进行几组简单的测试 左边是服务器又边上是客户端 Linux小命令 killall 是一个在 Unix 和类 Unix 操作系统上用于终止进程的命令。与 kill 命令不同killall 不是根据进程 IDPID来终止进程而是根据进程的名称来匹配并终止相应的进程。 killall [选项] 进程名 其中选项可以用来指定不同的操作行为而进程名则是要终止的进程的名称。 一些常用的选项包括 -e显示详细的错误信息。-i交互模式在终止进程之前询问用户。-q安静模式不显示任何输出。-u指定用户仅终止指定用户的进程。 注意killall 命令会终止所有匹配名称的进程因此需要谨慎使用以免意外终止系统中重要的进程
http://www.yingshimen.cn/news/58867/

相关文章:

  • 网站开发需要有什么证书目前流行的网站开发设计
  • 外贸网站主机选择html业务网站源码
  • 触屏版网站设计网站源码上传安装
  • 帝国做视频网站怎么创作自己的网站
  • 实惠高端网站设计品牌网络策划案怎么写
  • 山西两学一做登录网站什么the wordpress
  • 全新正版营销网站衡水阿里巴巴网站建设
  • 如何做弹幕网站北京市新闻
  • 湖北省住房部城乡建设厅网站dns上国外网站
  • 网站建设石家庄市公司网络维护主要做什么
  • 做网站除了有服务器还需要什么软件导购类网站怎么做
  • 哪些网站做渣土车租恁在手机上怎么做微电影网站
  • app网站平台建设方案搜索引擎推广的三种方式
  • wordpress中英网站插件国外搜索引擎网址
  • 如何加强企业网站建设论文网站宽度 自动收缩
  • 传媒公司营业执照单页网站seo如何优化
  • 做网站如何收益招商网站建设方案
  • 公司公司网站建设江门网站建设总部电话
  • php 建网站怎么做网站计划
  • 在线查看qq空间网站ps网页界面设计
  • 网站做seo的好处李沧做网站
  • 网站开发免费视频教程搜索引擎整合营销
  • 做特产的网站app开发公司 无冬
  • 保定网站设计多少钱苏州关键词优化公司
  • 公司网站建站流程什么软件做网站
  • WordPress无法发布外贸seo是什么意思啊
  • 怎样为网站做外链企业管理培训免费课程
  • 商业网站建设心得体会设计师网上接单被骗
  • 网站维护推广表深圳专业网站建
  • 中国建设局网站查询网络推广客户渠道