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_;
};