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

网络公司除了建网站wordpress手机版错误

网络公司除了建网站,wordpress手机版错误,视频模板免费,国外网站服务器建设目录 Sock.hpp TcpServer.hpp Protocol.hpp CalServer.cc CalClient.cc 分析 因为#xff0c;TCP面向字节流#xff0c;所以TCP有粘包问题#xff0c;故我们需要应用层协议来区分每一个数据包。防止读取到半个#xff0c;一个半数据包的情况。 Sock.hpp #pragma on…目录 Sock.hpp TcpServer.hpp Protocol.hpp CalServer.cc CalClient.cc 分析 因为TCP面向字节流所以TCP有粘包问题故我们需要应用层协议来区分每一个数据包。防止读取到半个一个半数据包的情况。 Sock.hpp #pragma once#include iostream #include string #include cstring #include unistd.h #include sys/types.h #include sys/socket.h #include arpa/inet.h #include netinet/in.h #include log.hpp// 对于一些TCP相关调用的封装 class Sock { private:const static int gback_log 20; public:int Socket(){// 1. 创建套接字成功返回对应套接字失败直接进程exitint listen_sock socket(AF_INET, SOCK_STREAM, 0); // 网络套接字, 面向字节流tcpif (listen_sock 0){logMessage(FATAL, create listen socket error, %d:%s, errno, strerror(errno));exit(2);}logMessage(NORMAL, create listen socket success: %d, listen_sock); // 1111Logreturn listen_sock;}void Bind(int sock, uint16_t port, std::string ip 0.0.0.0){// 2. bind注意云服务器不能绑定公网IP不允许。// 成功bind则成功bind失败进程exit(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 inet_addr(ip.c_str());if (bind(sock, (struct sockaddr *)local, sizeof local) 0){logMessage(FATAL, bind error, %d:%s, errno, strerror(errno));exit(3);}}void Listen(int sock){// 3. listen监听: 因为TCP是面向连接的在我们正式通信之前需要先建立连接// listen: 将套接字状态设置为监听状态。服务器要一直处于等待状态这样客户端才能随时随地发起连接。// 成功则成功失败则exitif (listen(sock, gback_log) 0) // gback_log后面讲全连接队列的长度。我猜测就是这个服务器同一时刻允许连接的客户端的数量最大值也不太对呀这么少么{logMessage(FATAL, listen error, %d:%s, errno, strerror(errno));exit(4);}logMessage(NORMAL, listen success);}// 一般经验// const std::string : 输入型参数// std::string *: 输出型参数// std::string : 输入输出型参数int Accept(int sock, uint16_t *port, std::string *ip){// accept失败进程不退出返回-1// 成功则返回对应的通信套接字struct sockaddr_in client;socklen_t len sizeof client;// 其实accept是获取已经建立好的TCP连接。建立好的连接在一个内核队列中存放最大数量的第二个参数1int service_sock accept(sock, (struct sockaddr *)client, len); // 返回一个用于与客户端进行网络IO的套接字不同于listen_sock// On success, these system calls return a nonnegative integer that is a descriptor for the accepted socket. On error, -1 is returned, and errno is set appropriately.if (service_sock 0){logMessage(ERROR, accept error, %d:%s, errno, strerror(errno));return -1; // accept失败不直接exit而是返回-1。因为在循环语句内部。}if (port)*port ntohs(client.sin_port);if (ip)*ip inet_ntoa(client.sin_addr);logMessage(NORMAL, link(accept) success, service socket: %d | %s:%d, service_sock,(*ip).c_str(), *port);return service_sock;}int Connect(int sock, const std::string ip, const uint16_t port){// 惯例写一下失败返回-1成功则客户端与服务端连接成功返回0struct sockaddr_in server;memset(server, 0, sizeof server);server.sin_family AF_INET;server.sin_addr.s_addr inet_addr(ip.c_str());server.sin_port htons(port);if (connect(sock, (struct sockaddr *)server, sizeof server) 0){return -1;}return 0;} public:Sock() default;~Sock() default; }; TcpServer.hpp #ifndef _TCP_SERVER_HPP_ #define _TCP_SERVER_HPP_#include Sock.hpp #include vector #include functional// 说实话这个TcpServer类实现的非常棒真的很棒网络和服务进行了解耦。 // 使用者直接BindServer, 然后start即可 namespace ns_tcpserver {using func_t std::functionvoid(int socket); // 服务器提供的服务方法类型void(int)可变class TcpServer;class ThreadData{public:ThreadData(int sock, TcpServer *server): _sock(sock), _server(server){}~ThreadData() {}public:int _sock;TcpServer *_server; // 因为静态成员函数呀};class TcpServer{// 不关心bind的ip和port因为用不到啊保留一个listen_sock用于accept就够了。private:int _listen_sock;Sock _sock;std::vectorfunc_t _funcs; // 服务器提供的服务private:static void *threadRoutine(void *args){pthread_detach(pthread_self()); // 线程分离避免类似于僵尸进程状态ThreadData *td (ThreadData *)args;td-_server-excute(td-_sock); // 提供服务close(td-_sock); // 保证四次挥手正常结束delete td;return nullptr;}public:TcpServer(const uint16_t port, const std::string ip 0.0.0.0){// 创建监听套接字bindlisten_listen_sock _sock.Socket();_sock.Bind(_listen_sock, port, ip);_sock.Listen(_listen_sock);}void start(){for (;;){// 开始accept然后执行任务std::string ip;uint16_t port; // 这两个东西也并没有传给线程。int sock _sock.Accept(_listen_sock, port, ip); // 后面是输出型参数if (sock -1)continue; // 本次accept失败循环再次accept。目前来看几乎不会// 连接客户端成功ip port已有。但是这里没用...pthread_t tid;ThreadData *td new ThreadData(sock, this);pthread_create(tid, nullptr, threadRoutine, (void *)td); // 新线程去提供service主线程继续accept}}void bindService(func_t service) // 暴露出去的接口用于设置该服务器的服务方法{_funcs.push_back(service);}void excute(int sock){for (auto func : _funcs){func(sock);}}~TcpServer(){if (_listen_sock 0)close(_listen_sock);}}; } #endif Protocol.hpp #ifndef _PROTOCOL_HPP_ #define _PROTOCOL_HPP_#include iostream #include string #include cstring #include sys/types.h #include sys/socket.h #include arpa/inet.h #include netinet/in.h #include jsoncpp/json/json.h// important and new namespace ns_protocol {// #define MYSELF 1 // 自己实现序列化反序列化还是使用json库#define SPACE #define SPACE_LENGTH strlen(SPACE) #define SEP \r\n #define SEP_LENGTH strlen(SEP)// 请求和回复都需要序列化和反序列化的成员函数// 序列化和反序列化双方都不同。但是添加报头和去报头是相同的Length\r\nxxxxx\r\n;// 客户端生成请求序列化之后发送给服务端class Request{public:Request() default;Request(int x, int y, char op): _x(x), _y(y), _op(op){}~Request() {}public:int _x;int _y;char _op;public:std::string serialize(){// 序列化为_x _op _y 注意序列化和添加报头是分开的反序列化和去掉报头是分开的 #ifdef MYSELFstd::string s std::to_string(_x);s SPACE;s _op;s SPACE;s std::to_string(_y);return s; #elseJson::Value root;root[x] _x;root[y] _y;root[op] _op;Json::FastWriter writer;return writer.write(root); #endif}bool deserialize(const std::string s){ #ifdef MYSELF// _x _op _ystd::size_t left s.find(SPACE);if (left std::string::npos)return false;std::size_t right s.rfind(SPACE);if (right left)return false;_x atoi(s.substr(0, left).c_str());_op s[left SPACE_LENGTH];_y atoi(s.substr(right SPACE_LENGTH).c_str()); #elseJson::Value root;Json::Reader reader;reader.parse(s, root);_x root[x].asInt();_y root[y].asInt();_op root[op].asInt(); #endifreturn true;}};// 服务端收到请求反序列化业务处理生成response序列化后发送给客户端class Response{public:Response(int result 0, int code 0): _result(result), _code(code){}~Response() {}public:std::string serialize(){// 序列化为_code _result 注意序列化和添加报头是分开的反序列化和去掉报头是分开的 #ifdef MYSELFstd::string s std::to_string(_code);s SPACE;s std::to_string(_result);return s; #elseJson::Value root;root[code] _code;root[result] _result;Json::FastWriter writer;return writer.write(root); #endif}bool deserialize(const std::string s){ #ifdef MYSELF// _code _resultstd::size_t pos s.find(SPACE);if (pos std::string::npos)return false;_code atoi(s.substr(0, pos).c_str());_result atoi(s.substr(pos SPACE_LENGTH).c_str()); #elseJson::Value root;Json::Reader reader;reader.parse(s, root);_result root[result].asInt();_code root[code].asInt(); #endifreturn true;}public:int _result;int _code; // 状态码, 防止除零模零和其他错误比如非法运算符运算符。code 0时result有效。};// 进行去报头报文完整则去报头并返回有效载荷不完整则代表失败返回空字符串。std::string deCode(std::string s) // 输入型输出型参数{// Length\r\nx op y\r\n 成功返回有效载荷失败返回空串std::size_t left s.find(SEP);if (left std::string::npos)return ;std::size_t right s.rfind(SEP);if (right left)return ;int length atoi(s.substr(0, left).c_str());if (length s.size() - left - 2 * SEP_LENGTH)return ; // 有效载荷长度不足不是一个完整报文其实经过上面两次的if判断已经够了可能。// 是一个完整报文进行提取std::string ret;s.erase(0, left SEP_LENGTH);ret s.substr(0, length);s.erase(0, length SEP_LENGTH);return ret;}std::string enCode(const std::string s){// Length\r\n11\r\nstd::string retStr std::to_string(s.size());retStr SEP;retStr s;retStr SEP;return retStr;}// 我真的很想用引用但是好像传统规则是输出型参数用指针...// 其实这个Recv就是一个单纯的读数据的函数将接收缓冲区数据读到应用层缓冲区中也就是*s中。存储的是对端发来的应用层报文。bool Recv(int sock, std::string *s){// 仅仅读取数据到*s中char buff[1024];ssize_t sz recv(sock, buff, sizeof buff, 0);if (sz 0){buff[sz] \0;*s buff; return true;}else if (sz 0){std::cout peer quit std::endl;return false;}else{std::cout recv error std::endl;return false;}}bool Send(int sock, const std::string s){ssize_t sz send(sock, s.c_str(), s.size(), 0);if (sz 0){return true;}else{std::cout send error! std::endl;return false;}} }#endif CalServer.cc #include TcpServer.hpp #include Protocol.hpp #include memoryusing namespace ns_tcpserver; using namespace ns_protocol;Response calculatorHelp(const Request req) {// 11???Response resp;int x req._x;int y req._y;switch (req._op){case :resp._result x y;break;case -:resp._result x - y;break;case *:resp._result x * y;break;case /:if (y 0)resp._code 1;elseresp._result x / y;break;case %:if (y 0)resp._code 2;elseresp._result x % y;break;default:resp._code 3;break;}return resp; }void calculator(int sock) {std::string s;for (;;){if (Recv(sock, s) 0) // 输出型参数break; // 大概率对端退出则服务结束。一般不会读取失败recv errorstd::string package deCode(s);if (package.empty())continue; // 不是一个完整报文继续读取因为TCP面向字节流// 读取到一个完整报文且已经去了应用层报头有效载荷在package中。如1 2Request req;req.deserialize(package);Response resp calculatorHelp(req);std::string backStr resp.serialize();backStr enCode(backStr);if (!Send(sock, backStr)) // 发送失败就退出break;} }// ./cal_server port int main(int argc, char **argv) {// std::cout test remake std::endl; // successif (argc ! 2){std::cout \nUsage: argv[0] port\n std::endl;exit(1);}std::unique_ptrTcpServer server(new TcpServer(atoi(argv[1])));server-bindService(calculator); // 给服务器设置服务方法将网络服务和业务逻辑进行解耦server-start(); // 服务器开始进行accept连接一个client之后就提供上方bind的服务return 0; } CalClient.cc #include Protocol.hpp #include Sock.hpp #include memoryusing namespace ns_protocol;// ./client serverIp serverPort int main(int argc, char **argv) {if (argc ! 3){std::cout \nUsage: argv[0] serverIp serverPort\n std::endl;exit(1);}Sock sock;int sockfd sock.Socket();// 客户端不需要显式bind, 老生常谈了。if (sock.Connect(sockfd, argv[1], atoi(argv[2])) -1){std::cout connect error std::endl;exit(3);}std::string backStr; // bool quit false;while (!quit){Request req;std::cout Please enter# ;std::cin req._x req._op req._y;std::string reqStr req.serialize();reqStr enCode(reqStr); // 添加应用层报头此处添加报头制定协议是为了解决TCP粘包问题因为TCP是面向字节流的。if (!Send(sockfd, reqStr))break;while (true){if (!Recv(sockfd, backStr)){quit true;break;}std::string package deCode(backStr);if(package.empty())continue; // 这次不是一个完整的应用层报文继续读取// 读取到一个完整的应用层报文且已经去报头获取有效载荷成功在package中。这个有效载荷是server发来的计算结果Response resp;resp.deserialize(package);switch (resp._code){case 1:std::cout 除零错误 std::endl;break;case 2:std::cout 模零错误 std::endl;break;case 3:std::cout 其他错误 std::endl;break;default:std::cout req._x req._op req._y resp._result std::endl;break;}break; // 退出防止TCP粘包问题的循环。}// 进行下一次获取用户输入进行计算。}close(sockfd);return 0; }分析 可以分为两个模块网络通信模块应用层模块包括应用层协议以及应用层计算器逻辑。 网络模块中Sock.hpp就是一个简单的对于系统调用的封装TcpServer.hpp的设计很优雅内部有一个std::vectorfunc_t _funcs;即这个server提供的服务。对外提供一个BindServer的方法可以指定这个服务器提供的服务。Start为服务器开始方法先accept获取与客户端建立好的连接然后创建新线程给客户端提供服务服务就是BindServer绑定的方法类型为void(int)。 应用层协议一个Request一个Response。分别是客户端的请求x,y,运算符和服务端的响应计算结果。这两个类都有序列化和反序列化的方法便于网络传输。还有一个Encode添加报头和Decode去报头的方法这个其实就是应用层协议的报头大体格式为 Length\r\nxxxx\r\n。目的就是解决TCP面向字节流所引起的粘包问题。 Recv内部就是一个recv调用将读取的网络数据添加到一个输出型参数string*指向string的结尾。因为TCP粘包问题所以可能读取的不是一个完整报文半个故在Decode方法内部也就是去报头时会检测此时是否有至少一个完整应用层报文。若有则去报头获取有效载荷。若没有则返回一个空串。上层可以通过判断是否为空串。判断是否读到了一个完整应用层报文若没有则再次Recv直到读到一个完整应用层报文为止。所以server和client在读取网络数据并去报头时都是在while循环内部进行的。
http://www.w-s-a.com/news/351106/

相关文章:

  • 怎么样做问卷网站多少钱英语
  • 房产网站建设方案建筑公司是干什么的
  • wordpress建的大型网站柳州市网站建设
  • 石家庄做网站的公司有哪些微信自媒体网站建设
  • 池州哪里有做网站注册公司有哪些风险
  • 做古代风格头像的网站对网站政务建设的建议
  • 网站搜索栏怎么做设计个网站要多少钱
  • 阿里巴巴网站建设目标wamp wordpress
  • 自己做的网站怎么挂网上金蝶erp
  • 网站的页面由什么组成淘宝网网站建设的需求分析
  • 软文网站推广法dede5.7内核qq个性门户网站源码
  • 个人备案网站名称校园网站建设特色
  • vr超市门户网站建设班级网站怎么做ppt模板
  • 网站建设一般是用哪个软件刚开始做写手上什么网站
  • 用jsp做的网站源代码下载有哪些做红色旅游景点的网站
  • 网站开发的技术选型黄石市网站建设
  • 做直播网站需要证书吗专做宝宝的用品网站
  • 网站标题用什么符号网站制作交易流程
  • dede模板网站教程jsp网站搭建
  • 上海网站开发外包公司鲜花导购网页制作
  • 宿州外贸网站建设公司个人注册网站一般做什么
  • 小公司做网站用哪种服务器什么是网站代理
  • 青岛李村网站设计公司cms建站平台
  • 做saas网站可行吗许昌抖音推广公司
  • 网站建设找谁做seo基础知识培训
  • 微网站怎么做的好建设网站不会写代码
  • 广州外贸网站制作wordpress信息搜索插件
  • 福建高端网站建设个人公众号怎么制作教程
  • 企业网站有哪些举几个例子wordpress ie兼容插件
  • 高端的深圳网站页面设计福清市建设局官方网站