序列化和反序列化(Linux)

1 序列化和反序列化

write和read实质是拷贝函数

1.1序列化和反序列化的概述

2网络版计算器

2.1代码实现

先把日志拷贝过来

2.1.1必须先要有网络功能

先把 TcpServer.hpp编写号

#pragma once
#include <cstdint>#include "Socket.hpp"
#include "./logs/ljwlog.h"class TcpServer
{
public:TcpServer(){}  bool InitServer(){}void Start(){}~TcpServer(){}
private:uint16_t port;};

2.1.2 把套接字接口封装一下方便使用

#pragma once#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <netinet/in.h>using namespace std;class Sock
{
public:Sock(){}~Sock(){}
public:void Socket()//创建套接字的接口{}void bind()//绑定的接口{}void Listen()//监听状态的接口{}int Accept()//获取连接的接口{}int Connect()//方便两个客户端和服务器都能使用这个Sock的这个公共方法{}private:int sockfd_;
};

2.1.3 TcpServer.hpp接口的补充

#pragma once
#include <cstdint>#include "Socket.hpp"
#include "./logs/ljwlog.h"class TcpServer
{
public:TcpServer(){}  bool InitServer(){//先创建套接字,再绑定,设置监听状态listensock_.Socket();listensock_.bind();listensock_.Listen();}void Start(){while(true){   int sockfd = listensock_.Accept();}}~TcpServer(){}
private:uint16_t port_;Sock listensock_; //叫listen套接字,Listen完后有真正的网络文件描述符
};

2.1.4 Sock.hpp接口的补充

#pragma once#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <cstring>
#include "./logs/ljwlog.h"using namespace std;enum{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){FATAL("Socket errno,error:%d,errstring:%s", errno, strerror(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;//ip默认0.0.0.0if(bind(sockfd_, (struct sockaddr*)&local, sizeof(local)) < 0){FATAL("Bind errno,error:%d,errstring:%s", errno, strerror(errno));exit(BindErr);            }}void Listen()//监听状态的接口{if(listen(sockfd_, backlog) < 0){FATAL("Listen errno,error:%d,errstring:%s", errno, strerror(errno));exit(ListenErr);   }}//              知道谁链接的我int Accept(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){WARN("accept error, %s: %d", strerror(errno), errno);return -1;}//网络转主机//拿出客户端的ip和端口号char ipstr[64];inet_ntop(AF_INET, &peer.sin_addr, ipstr, sizeof(ipstr));//网络转主机*clientip = ipstr;//网络转主机*clientport = ntohs(peer.sin_port);//网络转主机return newfd;}void Close(){close(sockfd_);}int Connect()//方便两个客户端和服务器都能使用这个Sock的这个公共方法{return 0;}private:int sockfd_;
};

2.1.4 TcpServer.hpp提供服务

2.1.5定制协议(Protocol)(约定好)

双方约定好,把请求放在Request(请求),结果放在Response(响应)

约定好了,最好就不要动他了

#pragma once#include<iostream>class Request
{
public:public: int x;int y;char op;// + - * / %
};class Response
{
public:public:int result;int code;// 0,可信,否则!0具体是几,表明对应的错误原因
};

2.1.6 (手写)序列化和反序列化

serialization 序列化(把struct 转换成 字符串)

deserialization 反序列化

2.1.6.1序列化

2.1.6.2反序列化

 2.1.6.3添加报头(要往网络里发 先添加报头)

这种

 

 2.1.6.4 提出有效载荷

2.1.6.5代码
#pragma once#include<iostream>
#include<string>
using namespace std;const string blank_space_sep = " ";//空格分隔符
const string protocol_sep = "\n";//报文分隔符//序列化和反序列化解决的是对应的是一个报文内部的问题
//还要解决一下报文与报文之间的问题//封装报头
string Encode(string &content)
{//封装报头  这里规定的协议就是长度+有效载荷string package = to_string(content.size());package += protocol_sep;package += content;package += protocol_sep;return package;
}//"len"\n"x op y"\n
string Decode(string &package)//将"x op y"提取出来
{return "";
}class Request
{
public: Request(int data1, int data2, char oper): x(data1), y(data2), op(oper){}public:bool serialization(string *out){//构建报文的有效载荷//序列化的就是把结构化的(struct)转成string,// "x op y"//数字之间是不可能出现分隔符的string s = to_string(x);s += blank_space_sep;s += op;s += blank_space_sep;s += to_string(y);*out = s;return true;}//"x op y"  进行分割bool deserialization(const string &in){size_t left = in.find(blank_space_sep);if(left == string::npos) return false;//没找到string part_x = in.substr(0, left);size_t right = in.rfind(blank_space_sep);//逆着找if(right == string::npos) return false;//没找到string part_y = in.substr(right + 1);if(left + 2 != right) return false;op = in[right -1];x = stoi(part_x);y = stoi(part_y);return true;}
public: int x;int y;char op;// + - * / %
};class Response
{
public:Response(int res, int c):result(res), code(c){}
public://序列化是结构体转字符串的bool serialization(string *out){// 序列化成这样"result code"//构建报文的有效载荷string s = to_string(result);s += blank_space_sep;s += to_string(code);*out = s;return true;}//反序列化 一定是你要传过来一个字符串bool deserialization(const string &in) //"result code" 协议定制好了就必须是这个样子{size_t pos = in.find(blank_space_sep);if(pos == string::npos) return false;//没找到string part_left = in.substr(0, pos);string part_right = in.substr(pos + 1);result = stoi(part_left);code = stoi(part_right);return true;} 
public:int result;int code;// 0,可信,否则!0具体是几,表明对应的错误原因
};
2.1.6.6 测试一下序列化和添加报头
#include<iostream>
#include "TcpServer.hpp"
#include "Protocol.hpp"using namespace std;int main()
{Request req(123, 456, '+');string s;req.serialization(&s);//序列化cout << s << endl;s = Encode(s);//给s报文添加报头cout << s ;//这是网络里发的样子return 0;
}

2.1.6.7 测试一下拿到报文的内容
#include<iostream>
#include "TcpServer.hpp"
#include "Protocol.hpp"using namespace std;int main()
{Request req(123, 456, '+');string s;req.serialization(&s);//序列化//cout << s << endl;s = Encode(s);//给s报文添加报头cout << s ;//这是网络里发的样子//拿到报文的内容string content;bool r = Decode(s, &content);cout<< content <<endl;return 0;
}

2.1.6.8 测试对收到报文进行反序列化  打散成对象

2.1.6.9 测试Response的要往网络里发 先添加报头

2.1.7.0 测试解码

2.1.7.1 测试Response反序列化

2.1.7.2 创建ServerCal.hpp处理整个报文

如何处理整个报文

把协议和网络功能组合在一起 然后再把这个头文件"ServerCal.hpp"交给ServerCal.cc

#pragma once
#include<string>
#include<string>
#include "Protocol.hpp"
using namespace std;//如何处理整个报文
//把协议和网络功能组合在一起 然后再把这个头文件"ServerCal.hpp"交给ServerCal.ccclass ServerCal
{
public:ServerCal(){}Response CalculatorHelper(const Request &req){Response resp(0, 0);switch(req.op){case '+':resp.result = req.x + req.y;case '-':resp.result = req.x - req.y;case '*':resp.result = req.x * req.y;           case '/':resp.result = req.x / req.y;}return resp;}//提供一个网络计算服务  把先把报文给我string Calculator(string &package)//肯定是收到一个序列化的请求报文{//收到一个请求报文 添加报头string content;bool r = Decode(package, &content);//报文不完整就直接返回if(!r) return;//完整的报文//请求的对象Request req;//反序列化r = req.deserialization(content);if(!r) return;//结果Response resp = CalculatorHelper(req);//返回结果//序列化string s;resp.serialization(&s);//序列化后,想把它当作网络报文发出去//添加报头s = Encode(s);return s;}~ServerCal(){}
};
2.1.7.3 完善一下TcpServer.hpp

2.1.7.4 测试

2.1.7.5 完善一下ClientCal.cc

tcp客户端要绑定,但不用显示的绑定

客户端端口号是随机的,但是唯一的

udp端口那里随机绑定是首次发送数据的时候,那么你的端口号就随之确定了

tcp这里是面向连接的,客户端连接成功了,我才想让你进行通信

没有bind 也就没有listen了

向服务器发起连接的接口 connect

客户端发起connect的时候,系统进行自动随机bind

#include <iostream>
#include <ctime>
#include <unistd.h>
#include <assert.h>
#include "Socket.hpp"
#include "Protocol.hpp"using namespace std;void Usage(const string &proc)
{cout << "\nUsage" << proc << "  serverip   serverport\n\n"<< endl;
}//./clientcal serverip serverport
int main(int argc, char *argv[])
{if (argc != 3){Usage(argv[0]);exit(0);}string serverip = argv[1];uint16_t serverport = stoi(argv[2]);Sock sockfd;sockfd.Socket();bool r = sockfd.Connect(serverip, serverport);if (!r)return 1;srand(time(nullptr));const string s = "+-*/^!~";int cnt = 10;string inbuffer_stream;while (cnt--){cout<< "第" <<cnt <<"次测试..." <<endl;int x = rand() % 100 + 1;usleep(1234);int y = rand() % 100 + 1;usleep(4321);char op = s[rand() % s.size()];Request req(x, y, op);req.DebugPrint();// 根据协议把请求发给服务器,Request是一个结构化的数据,发不了// 先序列化得到对应的字符串string package;req.serialization(&package);// 还是不能往网络里发送 添加报头还要//"len"\n"x op y"\npackage = Encode(package);cout << "这是最新的发出去的请求:\n"<< package;// 把请求往服务器端写write(sockfd.Fd(), package.c_str(), package.size());cout<<flush;// 接收服务器发回来的信息char buffer[128];//我们也没法保证我们能够读到一个完整的报文ssize_t n = read(sockfd.Fd(), buffer, sizeof(buffer));if (n > 0){buffer[n] = 0;inbuffer_stream += buffer;// "len"\n"result code"\nstring content;//解码bool r = Decode(inbuffer_stream, &content);//"result code"assert(r);//反序列化Response resp;r = resp.deserialization(content);assert(r);resp.DebugPrint();}sleep(1);}sockfd.Close();return 0;
}

2.1.7.6 客户端一次发多个请求呢

解决方案

2.1.7 (jsoncpp)序列化和反序列化

2.1.7.1 安装json库
sudo apt install libjsoncpp-dev

 这是头文件(只使用json.h)

2.1.7.2 简单的json的用法
#include<iostream>
#include "jsoncpp/json/json.h"using namespace std;int main()
{   Json::Value root;root["x"] = 100;root["y"] = 100;root["op"] = '+';//描述root["dect"] = "this is a + oper";//比较快的序列化Json::FastWriter w;string res = w.write(root);cout<< res <<endl;return 0;
}

编译时要带-ljsoncpp 

2.1.7.2.1 序列化 

2.1.7.2.2 反序列化 

2.1.7.2.3 json套json

2.1.7.3 Protocol.hpp中的json序列化和反序列化

2.1.7.4 守护进程化

3 重谈OSI七层模型

4 代码总合

4.1 ClientCal.cc

#include <iostream>
#include <ctime>
#include <unistd.h>
#include <assert.h>
#include "Socket.hpp"
#include "Protocol.hpp"using namespace std;void Usage(const string &proc)
{cout << "\nUsage" << proc << "  serverip   serverport\n\n"<< endl;
}//./clientcal serverip serverport
int main(int argc, char *argv[])
{if (argc != 3){Usage(argv[0]);exit(0);}string serverip = argv[1];uint16_t serverport = stoi(argv[2]);Sock sockfd;sockfd.Socket();bool r = sockfd.Connect(serverip, serverport);if (!r)return 1;srand(time(nullptr));const string s = "+-*/^!~";int cnt = 10;string inbuffer_stream;while (cnt--){cout<< "第" <<cnt <<"次测试..." <<endl;int x = rand() % 100 + 1;usleep(1234);int y = rand() % 100 + 1;usleep(4321);char op = s[rand() % s.size()];Request req(x, y, op);req.DebugPrint();// 根据协议把请求发给服务器,Request是一个结构化的数据,发不了// 先序列化得到对应的字符串string package;req.serialization(&package);// 还是不能往网络里发送 添加报头还要//"len"\n"x op y"\npackage = Encode(package);cout << "这是最新的发出去的请求:\n"<< package;// 把请求往服务器端写write(sockfd.Fd(), package.c_str(), package.size());// write(sockfd.Fd(), package.c_str(), package.size());// write(sockfd.Fd(), package.c_str(), package.size());// write(sockfd.Fd(), package.c_str(), package.size());// write(sockfd.Fd(), package.c_str(), package.size());// write(sockfd.Fd(), package.c_str(), package.size());cout<<flush;// 接收服务器发回来的信息char buffer[128];//我们也没法保证我们能够读到一个完整的报文ssize_t n = read(sockfd.Fd(), buffer, sizeof(buffer));if (n > 0){buffer[n] = 0;inbuffer_stream += buffer;// "len"\n"result code"\ncout<< inbuffer_stream <<endl;string content;//解码bool r = Decode(inbuffer_stream, &content);//"result code"assert(r);//反序列化Response resp;r = resp.deserialization(content);assert(r);resp.DebugPrint();}sleep(1);}sockfd.Close();return 0;
}

4.2 makefile

.PHONY:all
all:servercal clientcal
servercal:ServerCal.ccg++ -g -o $@ $^ -lpthread -std=c++11 -ljsoncpp
clientcal:ClientCal.ccg++ -o $@ $^ -lpthread -std=c++11 -ljsoncpp
.PHONT:clean
clean:rm -f clientcal servercal

4.3 Protocol.hpp

#pragma once#include<iostream>
#include<string>
#include "jsoncpp/json/json.h"
using namespace std;const string blank_space_sep = " ";//空格分隔符
const string protocol_sep = "\n";//报文分隔符//序列化和反序列化解决的是对应的是一个报文内部的问题
//还要解决一下报文与报文之间的问题//添加报头  "len"\n"x op y"\n
string Encode(string &content)
{//封装报头  这里规定的协议就是长度+有效载荷string package = to_string(content.size());package += protocol_sep;package += content;package += protocol_sep;return package;
}//将"x op y"提取出来 有效载荷
//"len"\n"x op y"\n   package整个报文    *content把结果带出去
bool Decode(string &package, string *content)
{size_t pos = package.find(protocol_sep);if(pos == string::npos) return false;string len_str = package.substr(0, pos);size_t len = stoi(len_str); //拿到了len长度//判断一下package的长度够不够//package = len_str + content_str + 2size_t total_len = len_str.size() + len + 2;if(package.size() < total_len) return false;//大于没事,因为肯定有完整的报文//*content把结果带出去  "x op y"*content = package.substr(pos + 1, len);// earse 移除报文  package.erase(0, total_len);return true;
}class Request
{
public: Request(int data1, int data2, char oper): x(data1), y(data2), op(oper){}Request(){}
public:bool serialization(string *out){// //构建报文的有效载荷// //序列化的就是把结构化的(struct)转成string,// // "x op y"// //数字之间是不可能出现分隔符的// string s = to_string(x);// s += blank_space_sep;// s += op;// s += blank_space_sep;// s += to_string(y);// *out = s;// return true;//Json 序列化Json::Value root;root["x"] = x;root["y"] = y;root["op"] = op;Json::FastWriter w;*out = w.write(root);return true;}//"x op y"  进行分割bool deserialization(const string &in){// size_t left = in.find(blank_space_sep);// if(left == string::npos) return false;//没找到// string part_x = in.substr(0, left);// size_t right = in.rfind(blank_space_sep);//逆着找// if(right == string::npos) return false;//没找到// string part_y = in.substr(right + 1);// if(left + 2 != right) return false;// op = in[right -1];// x = stoi(part_x);// y = stoi(part_y);// return true;//Json 反序列化Json::Value root;Json::Reader r;r.parse(in, root);//反序列化到root//提取出来x = root["x"].asInt();y = root["y"].asInt();op = root["op"].asInt();return true;  }void DebugPrint(){cout<< "新请求构建完成" << x << op << y << "=?" <<endl<<endl;}public: int x;int y;char op;// + - * / %
};class Response
{
public:Response(int res, int c):result(res), code(c){}Response(){}
public://序列化是结构体转字符串的bool serialization(string *out){// // 序列化成这样"result code"// //构建报文的有效载荷// string s = to_string(result);// s += blank_space_sep;// s += to_string(code);// *out = s;// return true;//Json 序列化Json::Value root;root["result"] = result;root["code"] = code;Json::FastWriter w;*out = w.write(root);return true;}//反序列化 一定是你要传过来一个字符串bool deserialization(const string &in) //"result code" 协议定制好了就必须是这个样子{// size_t pos = in.find(blank_space_sep);// if(pos == string::npos) return false;//没找到// string part_left = in.substr(0, pos);// string part_right = in.substr(pos + 1);// result = stoi(part_left);// code = stoi(part_right); // return true;//Json 反序列化Json::Value root;Json::Reader r;r.parse(in, root);//反序列化到root//提取出来result = root["result"].asInt();code = root["code"].asInt();return true;} void DebugPrint(){cout<< "响应结果完成" << "result:"<< result <<"code:" <<code <<endl <<endl;}
public:int result;int code;// 0,可信,否则!0具体是几,表明对应的错误原因
};

4.4 ServerCal.cc

#include<iostream>
#include<unistd.h>
#include "TcpServer.hpp"
#include "Protocol.hpp"
#include "ServerCal.hpp"using namespace std;void Usage(const string& proc)
{cout<<"\nUsage" << proc << "port\n\n" <<endl;
}int main(int argc, char* argv[])
{if(argc != 2){Usage(argv[0]);exit(0);   }uint16_t port = stoi(argv[1]);ServerCal cal;TcpServer *tsvp = new TcpServer(port, bind(&ServerCal::Calculator, &cal, placeholders::_1));tsvp->InitServer();daemon(0, 0);tsvp->Start();// Response resp(1000, 0);// //发回去// string content;// resp.serialization(&content);// //cout << content << endl;// //要往网络里发 先添加报头// string package = Encode(content);// cout << package << endl;// //解码 放进s// string s;// bool r = Decode(package, &s);// cout<< s <<endl;// //反序列化   打散成对象// Response temp;// temp.deserialization(s);// cout<<"\n\n";// cout<< temp.result <<endl;// cout<< temp.code << endl;// Request req(123, 456, '+');// string s;// req.serialization(&s);//序列化// //cout << s << endl;// s = Encode(s);//给s报文添加报头// cout << s ;//这是网络里发的样子// //拿到报文的内容// string content;// bool r = Decode(s, &content);// cout<< content <<endl;// //对收到报文进行反序列化  打散成对象// Request temp;// temp.deserialization(content);// cout<< temp.x <<endl << temp.op <<endl << temp.y <<endl;return 0;
}

4.5 ServerCal.hpp

#pragma once
#include<string>
#include<string>
#include "Protocol.hpp"
using namespace std;//如何处理整个报文
//把协议和网络功能组合在一起 然后再把这个头文件"ServerCal.hpp"交给ServerCal.ccclass ServerCal
{
public: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 = 1;else {resp.result = req.x / req.y;}break;default:resp.code = 2;break;}return resp;}//提供一个网络计算服务  把先把报文给我//           package: "len"\n"10 + 20"\nstring Calculator(string &package)//肯定是收到一个序列化的请求报文{//收到一个请求报文 添加报头string content;bool r = Decode(package, &content);//报文不完整就直接返回if(!r) return "";//完整的报文//请求的对象Request req;//反序列化r = req.deserialization(content);if(!r) return "";//结果Response resp = CalculatorHelper(req);//返回结果//序列化string s;resp.serialization(&s);//序列化后,想把它当作网络报文发出去//添加报头s = Encode(s);return s;}~ServerCal(){}
};

4.6 Socket.hpp

#pragma once#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <cstring>
#include "./logs/ljwlog.h"using namespace std;enum
{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){FATAL("Socket errno,error:%d,errstring:%s", errno, strerror(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; // ip默认0.0.0.0if (bind(sockfd_, (struct sockaddr *)&local, sizeof(local)) < 0){FATAL("Bind errno,error:%d,errstring:%s", errno, strerror(errno));exit(BindErr);}}void Listen() // 监听状态的接口{if (listen(sockfd_, backlog) < 0){FATAL("Listen errno,error:%d,errstring:%s", errno, strerror(errno));exit(ListenErr);}}//              知道谁链接的我int Accept(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){WARN("accept error, %s: %d", strerror(errno), errno);return -1;}// 网络转主机// 拿出客户端的ip和端口号char ipstr[64];inet_ntop(AF_INET, &peer.sin_addr, ipstr, sizeof(ipstr)); // 网络转主机*clientip = ipstr;                                        // 网络转主机*clientport = ntohs(peer.sin_port);                       // 网络转主机return newfd;}void Close(){close(sockfd_);}int Connect(const string &ip, const uint16_t &port) // 方便两个客户端和服务器都能使用这个Sock的这个公共方法{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){cerr << "connect to" << ip << "::" << port <<"error"<< endl;return false;}return true;}int Fd(){return sockfd_;}private:int sockfd_;
};

4.7 TcpServer.hpp

#pragma once
#include <cstdint>
#include <signal.h>
#include <functional>
#include "Socket.hpp"
#include "./logs/ljwlog.h"//                     返回值    参数
using fun_t = function< string(string &package)>;class TcpServer
{
public:TcpServer(uint16_t port, fun_t callback):port_(port), callback_(callback){}  bool InitServer( ){//先创建套接字,再绑定,设置监听状态listensock_.Socket();listensock_.Bind(port_);listensock_.Listen();INFO("init server");return true;}void Start(){signal(SIGCHLD, SIG_IGN);//忽略就不用等待了signal(SIGPIPE, SIG_IGN);//忽略就不用等待了while(true){   string clientip;uint16_t clientport;int sockfd = listensock_.Accept(&clientip, &clientport);if(sockfd < 0) continue;INFO("Accept server   sockfd:%d  clientip:%s  clientport:%d", sockfd, clientip.c_str(), clientport);//提供服务if(fork() == 0){//子进程listensock_.Close();//请求的信息流string inbuffer_stream;//数据计算while(true){//从网络当中读数据到buffer当中char buffer[1024];ssize_t n = read(sockfd, buffer, sizeof(buffer));if(n > 0){buffer[n] = 0;inbuffer_stream += buffer;DEBUG("inbuffer_stream: %s", inbuffer_stream.c_str());while(true){string info = callback_(inbuffer_stream);//如果没有读到完整的报文,就会返回一个空串infpif(info.empty()) break;write(sockfd, info.c_str(), info.size());}}else if(n == 0) break;else break;}exit(0);}close(sockfd);//不用等了直接关就好了}}~TcpServer(){}
private:uint16_t port_;Sock listensock_; //叫listen套接字,Listen完后有真正的网络文件描述符fun_t callback_;
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/31639.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

关于ngx-datatable no data empty message自定义模板解决方案

背景&#xff1a;由于ngx-dataable插件默认没有数据时显示的文案是no data to display&#xff0c;且没有任何样式。这里希望通过自定义模板来实现。但目前github中有一个案例是通过设置代码&#xff1a; https://swimlane.github.io/ngx-datatable/empty** <ngx-datatable…

opencv 图片颜色+轮廓识别

目标图片&#xff1a; 1 简单识别图片中出现颜色最多的 import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException;public class SimpleImageColorRecognizer implements ImageColorRecogniz…

文件系统调用(上) ─── linux第17课

目录 linux 中man 2和man 3的区别 文件内容介绍 C语言文件接口 示例: 输出信息到显示器&#xff0c;你有哪些方法 总结: 系统文件I/O 文件类的系统调用接口介绍 示例 open 函数具体使用哪个,和具体应用场景相关&#xff0c; write read close lseek ,类比C文件相关接…

vue3-element-admin 前后端本地启动联调

一、后端环境准备 1.1、下载地址 gitee 下载地址 1.2、环境要求 JDK 17 1.3、项目启动 克隆项目 git clone https://gitee.com/youlaiorg/youlai-boot.git数据库初始化 执行 youlai_boot.sql 脚本完成数据库创建、表结构和基础数据的初始化。 修改配置 application-dev.y…

证券行业SCA开源风险治理实践

近日&#xff0c;悬镜安全成功中标国内领先的证券公司海通证券软件成分分析工具采购项目&#xff0c;中标产品为源鉴SCA开源威胁管控平台。 海通证券作为国内领先的证券公司之一&#xff0c;当下已基本建成涵盖证券期货经纪、投行、自营、资产管理、私募股权投资、另类投资、融…

JVM内存结构笔记(上)

文章目录 前言运行时数据区域1.程序计数器定义特点总结 2.虚拟机栈2.1 定义局部变量表 ★操作数栈动态链接方法返回地址(方法出口) 2.2 栈内存溢出演示栈内存溢出 java.lang.StackOverflowError 2.3问题辨析1. 垃圾回收是否涉及栈内存&#xff1f;2. 栈内存分配越大越好吗&…

使用 Miniforge3 管理 Python 环境的详细指南(基于最新实践和时效性信息,截至 2025 年)

以下是使用 Miniforge3 管理 Python 环境的详细指南&#xff08;基于最新实践和时效性信息&#xff0c;截至 2025 年&#xff09;&#xff1a; 一、Miniforge3 简介 Miniforge3 是一个轻量级 Conda 环境管理工具&#xff0c;默认使用 conda-forge 软件源&#xff08;社区维护的…

【python|二分|leetcode441】一题搞清楚二分区间问题---闭区间、左闭右开、左开右闭、全开区间

every blog every motto: Although the world is full of suffering&#xff0c; it is full also of the overcoming of it 0. 前言 一题搞清楚二分区间问题—闭区间、左闭右开、左开右闭、全开区间 0.1 题目&#xff1a;Problem: 441. 排列硬币 你总共有 n 枚硬币&#x…

【NLP 34、实践 ⑧ 基于faq知识库和文本匹配算法进行意图识别】

目录 一、demo1_similarity_function.py 二、demo2_bm25.py 三、基于faq知识库和文本匹配算法的意图识别 1.初始化 2.加载BM25模型 3.加载Word2Vec模型 4.文本向量化 5.加载知识库 6.查询方法 7.模型测试 正是江南好时节&#xff0c;落花时节又逢君 —— 25.3.7 一、demo1_sim…

机器人交互系统 部署构建

环境要求 Ubuntu 20.04 或更高版本ROS Noetic 或兼容版本Python 3.8 安装步骤 1. 安装ROS环境&#xff08;如未安装&#xff09; sudo apt update sudo apt install ros-noetic-desktop-full source /opt/ros/noetic/setup.bash2. 创建工作空间并克隆代码 mkdir -p ~/code…

每日一题——两数相加

两数相加 问题描述问题分析解题思路代码实现代码解析注意事项示例运行总结 问题描述 给定两个非空链表&#xff0c;表示两个非负整数。链表中的每个节点存储一个数字&#xff0c;数字的存储顺序为逆序&#xff08;即个位在链表头部&#xff09;。要求将这两个数字相加&#xff…

ResNet50深度解析:原理、结构与PyTorch实现

ResNet50深度解析&#xff1a;原理、结构与PyTorch实现 1. 引言 ResNet&#xff08;残差网络&#xff09;是深度学习领域的一项重大突破&#xff0c;它巧妙解决了深层神经网络训练中的梯度消失/爆炸问题&#xff0c;使得构建和训练更深的网络成为可能。作为计算机视觉领域的里…

政安晨【零基础玩转各类开源AI项目】Wan 2.1 本地部署,基于ComfyUI运行,最强文生视频 图生视频,一键生成高质量影片

政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff01; 目录 下载项目 创建虚拟环境 安装项目依赖 尝试运行 依次下载模型 完成 我们今天要使…

每日一题----------String 和StringBuffer和StringBuiler重点

本质&#xff1a;是一个char字符数组存储字符串 总结&#xff1a; 1.如果字符串存在大量的修改操作&#xff0c;一般使用StringBuffer或者StringBuilder。 2.如果字符串存在大量的修改操作&#xff0c;并且单线程的情况&#xff0c;使用StringBuilder。 3.如果字符串存在大…

35.HarmonyOS NEXT Layout布局组件系统详解(二):AutoRow行组件实现原理

HarmonyOS NEXT Layout布局组件系统详解&#xff08;二&#xff09;&#xff1a;AutoRow行组件实现原理 文章目录 HarmonyOS NEXT Layout布局组件系统详解&#xff08;二&#xff09;&#xff1a;AutoRow行组件实现原理1. AutoRow组件概述2. AutoRow组件接口定义3. AutoRow组件…

Java 集合框架大师课:集合框架源码解剖室(五)

&#x1f525;Java 集合框架大师课&#xff1a;集合框架源码解剖室&#xff08;五&#xff09; &#x1f4a3; 警告&#xff1a;本章包含大量 裸码级硬核分析&#xff0c;建议搭配咖啡因饮料阅读&#xff01;☕️ 第一章 ArrayList 的扩容玄学 1.1 动态扩容核心代码大卸八块 …

Kubernetes服务部署 —— Kafka

1、简介 Kafka和zookeeper是两种典型的有状态的应用集群服务。首先kafka和zookeeper都需要存储盘来保存有状态信息&#xff1b;其次kafka和zookeeper每一个实例都需要有对应的实例Id (Kafka需broker.id, zookeeper需要my.id) 来作为集群内部每个成员的标识&#xff0c;集群内节…

计算机网络基础知识

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/literature?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;…

电脑的写字板如何使用?

打开写字板&#xff1a; 直接按一下键盘上的win R 键&#xff0c;然后输入&#xff1a;write &#xff0c; 再按一下回车 , 即可打开写字板 可以在里面写文字 和 插入图片等… &#xff0c; 如下所示&#xff1a; 保存写字板内容&#xff1a; 当我们写好了之后&#xff0c;…

用vector实现栈的功能

要注意pop_back和back()的区别 #include <bits/stdc.h> using namespace std;void Push(vector<int> &v,int x) {v.push_back(x); }void Top(vector<int> &v) {if(!v.empty()){cout<<v.back()<<endl;// v.pop_back();}else {cout<&l…