#pragma once
#include "Protocol.hpp"
#include "Socket.hpp"
#include
#include "log.hpp"
#include
using func_t = function<string(string &)>;
class TcpServer
{
public:
TcpServer(const uint16_t &port, func_t callback)
: _port(port), _callback(callback)
{
}
~TcpServer()
{
}
bool InitServer()
{
// 创建套接字
_listenSock.Socket();
int sockfd = _listenSock.Sockfd();
//设置端口复用
int opt = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt));
// 绑定
_listenSock.Bind(_port);
// 监听
_listenSock.Listen();
log(Info, "Init server successed...");
return true;
}
void Start()
{
// 守护进程化
//参数中的第一个0表示更改该进程的路径为根目录执行,第二个0表示
//把0,1,2三个文件描述符输出的东西重定向到 /dev/null 文件中
daemon(0,0);
// 屏蔽一些信号
signal(SIGPIPE, SIG_IGN);
signal(SIGCHLD, SIG_IGN);
while (true)
{
string clientip;
uint16_t clientport;
int sockfd = _listenSock.Accept(clientip, clientport);
if (sockfd > 0)
{
if (fork() == 0)
{
// 子进程继承了父进程的监听套接字,但是并用不上,所以可以close掉
_listenSock.Close();
// 提供服务
string inbuffer_stream;
while (true)
{
char tmp[10240];
bzero(tmp, sizeof(tmp));
ssize_t n = read(sockfd, tmp, sizeof(tmp) - 1);
if (n > 0)
{
tmp[n] = '\0';
inbuffer_stream += tmp;
cout<<"=========================="<<endl;
cout<<inbuffer_stream<<endl;
cout<<"=========================="<<endl;
string ret;
while (true)
{
//只要返回的不是一个空字符串,就说明请求还没有
//处理完,那么就继续处理剩下的请求,把处理结果
//存在ret中
string str = _callback(inbuffer_stream);
if (str.empty())
{
break;
}
ret+=str;
}
//把请求发送给客户端
write(sockfd, ret.c_str(), ret.size());
}
else if (n == 0)
{
log(Info, "client exit...");
break;
}
else
{
log(Fatal, "read failed,errno:%d,errstring:%s", errno, strerror(errno));
break;
}
}
close(sockfd);
exit(0);
}
close(sockfd);
}
}
}
private:
Sock _listenSock;
uint16_t _port;
func_t _callback;
};
#pragma once
#include
#include "Protocol.hpp"
enum
{
DivZeroErr,
ModZeroErr,
OtherErr
};
class ServerCal
{
public:
ServerCal()
{
}
~ServerCal()
{
}
Response CalculatorHelper(const Request &req)
{
Response resp(0, 0);
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 = DivZeroErr;
break;
}
resp._result = x / y;
break;
}
case '%':
{
if (y == 0)
{
resp._code = ModZeroErr;
break;
}
resp._result = x % y;
break;
}
default:
{
resp._code = OtherErr;
break;
}
}
return resp;
}
//package: "len"\n"1 + 1"\n
string Calculator(string& package)
{
string content;
//解码
bool ret=Decode(package,content);
if(!ret)
{
return "";
}
cout<<"///"<<endl;
cout<<package<<endl;
cout<<"///"<<endl;
Request req;
//反序列化
ret=req.Request_DeSerialize(content);
if(!ret)
{
return "";
}
cout<<"get a new task:";
printf("%d %c %d\n",req._x,req._op,req._y);
//传入请求,返回响应
Response resp=CalculatorHelper(req);
//序列化
string resp_str=resp.Response_Serialize();
//添加报头
Encode(resp_str);
return resp_str;
}
};
#include
using namespace std;
#include "ServerCal.hpp"
#include "Protocol.hpp"
#include "TcpServer.hpp"
#include
// int main()
// {
// Request req(145,20,'%');
// string ret=req.Request_Serialize();
// Encode(ret);
// cout<
// cout<
// Request r;
// r.Request_DeSerialize(ret);
// cout<
// cout<
// cout<
// string content;
// Decode(ret,content);
// cout<
// // Response resp(10,0);
// // string ret=resp.Response_Serialize();
// // Encode(ret);
// // cout<
// // string content;
// // Decode(ret,content);
// // cout<
// // Response r;
// // r.Response_DeSerialize(content);
// // cout<
// // cout<
// return 0;
// }
void Usage(string proc)
{
cout<<"\n\t";
cout<<"Usage: "<<proc<<" serverPort"<<endl<<endl;
}
//Usage: ./servercal
int main(int argc,char* argv[])
{
if(argc!=2)
{
Usage(argv[0]);
exit(1);
}
uint16_t serverPort=(uint16_t)stoi(argv[1]);
ServerCal cal;
//服务器绑定的是Calculator函数,该函数有两个参数,一个绑定为Calculator的this指针,另一个参数自己传
unique_ptr<TcpServer> svr(new TcpServer(serverPort,bind(&ServerCal::Calculator,&cal,placeholders::_1)));
//初始化
svr->InitServer();
//启动
svr->Start();
return 0;
}
#pragma once
#include
using namespace std;
#include "log.hpp"
#include
const static string blank_space_sep = " ";
const static string protocol_sep = "\n";
// #define MySelf
extern Log log;
// 添加报头和分隔符
void Encode(string &content)
{
size_t len = content.size();
content = to_string(len) + protocol_sep + content + protocol_sep;
}
// 去掉报头,如果解码成功,则继续移除报文,否则,直接返回false
bool Decode(string &package, string &content)
{
size_t pos = package.find(protocol_sep);
// 找不到\n不一定是报文的格式错误,也有可能是报文不完整导致的,所以这里
// 无需打错误日志信息
if (pos == string::npos)
{
// log(Warning, "this package format is failed,package:%s", package.c_str());
return false;
}
string len_str = package.substr(0, pos);
size_t len = stoi(len_str);
size_t total_len = len_str.size() + len + 2;
if (package.size() < total_len)
{
log(Warning, "this package format is failed,package:%s", package.c_str());
return false;
}
content = package.substr(pos + 1, len);
// 解码成功则移除报文
package.erase(0, total_len);
return true;
}
class Request
{
public:
Request()
{
}
Request(int data1, int data2, char oper)
: _x(data1), _y(data2), _op(oper)
{
}
~Request()
{
}
// 序列化,即把结构化的数据序列化成字符串
// 格式:"len"\n"x [+-*/%] y"\n
string Request_Serialize()
{
#ifdef MySelf
string content;
content += to_string(_x);
content += blank_space_sep;
content += _op;
content += blank_space_sep;
content += to_string(_y);
return content;
#else
//用第三方库jsoncpp进行序列化
//Json::Value是一个key:value的万能对象
Json::Value root;
root["x"] = _x;
root["op"] = _op;
root["y"] = _y;
Json::FastWriter w;
string content = w.write(root);
return content;
#endif
}
// 反序列化
bool Request_DeSerialize(const string &content_str)
{
#ifdef MySelf
size_t left = content_str.find(blank_space_sep);
if (left == string::npos)
{
log(Warning, "this content_str format is failed,content_str:%s", content_str.c_str());
return false;
}
//取出content_str的前半部分
string left_str = content_str.substr(0, left);
size_t right = content_str.rfind(blank_space_sep);
if (right == string::npos)
{
log(Warning, "this content_str format is failed,content_str:%s", content_str.c_str());
return false;
}
//取出content_str的后半部分
string right_str = content_str.substr(right + 1);
if (left + 2 != right)
{
log(Warning, "this content_str format is failed,content_str:%s", content_str.c_str());
return false;
}
_x = stoi(left_str);
_y = stoi(right_str);
_op = content_str[left + 1];
return true;
#else
//万能对象
Json::Value v;
Json::Reader r;
//把字符串形式的content_str变成结构化的数据,并写到万能对象中去
r.parse(content_str, v);
_x = v["x"].asInt();
_op = v["op"].asInt();
_y = v["y"].asInt();
return true;
#endif
}
public:
int _x;
int _y;
char _op;
};
class Response
{
public:
Response()
{
}
Response(const int &result, const int &code = 0)
: _result(result), _code(code)
{
}
~Response()
{
}
// 格式:"len"\n"result code"\n
string Response_Serialize()
{
#ifdef MySelf
string package;
string result_str = to_string(_result);
string code_str = to_string(_code);
size_t body_len = result_str.size() + code_str.size();
package += result_str;
package += blank_space_sep;
package += code_str;
return package;
#else
// 万能对象
Json::Value root;
root["result"] = _result;
root["code"] = _code;
Json::FastWriter w;
string package = w.write(root);
return package;
#endif
}
bool Response_DeSerialize(const string &content_str)
{
#ifdef MySelf
size_t content_left = content_str.find(blank_space_sep);
if (content_left == string::npos)
{
log(Warning, "this content_str format is failed,content_str:%s", content_str.c_str());
return false;
}
string content_left_str = content_str.substr(0, content_left);
string content_right_str = content_str.substr(content_left + 1);
_result = stoi(content_left_str);
_code = stoi(content_right_str);
return true;
#else
//Json::Value v是万能对象
Json::Value v;
Json::Reader r;
r.parse(content_str,v);
_result=v["result"].asInt();
_code=v["code"].asInt();
return true;
#endif
}
public:
int _result;
int _code = 0;
};
#pragma once
#include
using namespace std;
#include
#include
#include
#include
#include "log.hpp"
#include
#include
#include
#include
int backlog = 10;
enum
{
SockErr = 2,
BindErr,
ListenErr,
ConnectErr,
};
class Sock
{
public:
Sock()
: _sockfd(-1)
{
}
~Sock()
{
if(_sockfd>0)
{
close(_sockfd);
}
}
// 创建套接字
void Socket()
{
_sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (_sockfd < 0)
{
log(Fatal, "socket failed,errno:%d,errstring:%s", errno, strerror(errno));
exit(SockErr);
}
log(Info, "socket successed, sockfd:%d", _sockfd);
}
// 绑定
void Bind(const uint16_t &serverPort)
{
struct sockaddr_in local;
bzero(&local, sizeof(local));
local.sin_family = AF_INET;
local.sin_port = htons(serverPort);
local.sin_addr.s_addr = INADDR_ANY;
if (bind(_sockfd, (struct sockaddr *)(&local), sizeof(local)) < 0)
{
log(Fatal, "bind failed,errno:%d,errstring:%s", errno, strerror(errno));
exit(BindErr);
}
log(Info, "bind successed...");
}
// 监听
void Listen()
{
if (listen(_sockfd, backlog) < 0)
{
log(Fatal, "set listen state failed,errno:%d,errstring:%s", errno, strerror(errno));
exit(ListenErr);
}
log(Info, "set listen state successed");
}
//获取连接
int Accept(string& clientip,uint16_t& clientport)
{
struct sockaddr_in client;
socklen_t len=sizeof(client);
bzero(&client,sizeof(client));
int sockfd=accept(_sockfd,(struct sockaddr*)(&client),&len);
if(sockfd<0)
{
log(Warning, "accept new link failed,errno:%d,errstring:%s", errno, strerror(errno));
return -1;
}
log(Info,"accept a new link...,sockfd:%d",sockfd);
clientip=inet_ntoa(client.sin_addr);
clientport=(uint16_t)(ntohs(client.sin_port));
return sockfd;
}
// 连接
void Connect(const string &serverIp, const uint16_t &serverPort)
{
struct sockaddr_in server;
bzero(&server, sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr(serverIp.c_str());
server.sin_port = htons(serverPort);
if (connect(_sockfd, (struct sockaddr *)(&server), sizeof(server)) < 0)
{
log(Fatal, "connect server failed,errno:%d,errstring:%s", errno, strerror(errno));
exit(ConnectErr);
}
log(Info, "connect server succeeded...");
}
void Close()
{
if(_sockfd>0)
{
close(_sockfd);
}
}
int Sockfd()
{
return _sockfd;
}
private:
int _sockfd;
};
.PHONY:all
all:servercal clientcal
servercal:ServerCal.cc
g++ -o $@ $^ -std=c++11 -ljsoncpp
clientcal:ClientCal.cc
g++ -o $@ $^ -std=c++11 -ljsoncpp
.PHONY:clean
clean:
rm -f clientcal servercal
#include
using namespace std;
#include "Socket.hpp"
#include "Protocol.hpp"
#include
void Usage(string proc)
{
cout << "\n\t";
cout << "Usage: " << proc << " serverip serverPort" << endl
<< endl;
}
// Usage: ./servercal
int main(int argc, char *argv[])
{
if (argc != 3)
{
Usage(argv[0]);
exit(1);
}
srand(time(nullptr));
string serverIp = argv[1];
uint16_t serverPort = (uint16_t)stoi(argv[2]);
// 创建套接字
Sock sock;
sock.Socket();
// 连接
sock.Connect(serverIp, serverPort);
string oper = "+-*/%&^$@#";
int sockfd = sock.Sockfd();
string package;
while (true)
{
int x = rand() % 100 + 1;
int y = rand() % 100;
char op = oper[rand() % oper.size()];
//构建请求
Request req(x, y, op);
//序列化
string req_str = req.Request_Serialize();
cout << "req:" << req_str << endl;
//添加报头
Encode(req_str);
cout << "这是最新的需要发到网络上去的报文:" << endl;
cout << req_str << endl;
write(sockfd, req_str.c_str(), req_str.size());
char buffer[10240];
bzero(buffer, sizeof(buffer));
int n = read(sockfd, buffer, sizeof(buffer) - 1);
if (n > 0)
{
buffer[n] = '\0';
package += buffer;
while (true)
{
string content;
Response resp;
//解码
bool ret = Decode(package, content);
if(!ret)
{
//如果解码失败,说明package出问题了或者package中的
//内容不是一个完整的报文,跳出本层循环
break;
}
//来到这里说明解码成功
cout << content << endl;
//反序列化
resp.Response_DeSerialize(content);
cout << "len : " << content.size() << endl;
cout << "resp._result : " << resp._result << endl;
cout << "resp._code : " << resp._code << endl;
}
}
else if (n == 0)
{
cout << "server quit..." << endl;
break;
}
else
{
perror("read failed");
break;
}
sleep(10);
}
sock.Close();
return 0;
}
#pragma once
#include
using namespace std;
#include
#include
#include
#include
#include
#include
#include
// 日志等级
#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 SIZE 1024
#define LogFile "log.txt"
class Log
{
public:
Log()
{
printMethod = Screen;
path = "./log/";
}
void Enable(int mothod)
{
printMethod = mothod;
}
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 string& logtxt)
{
switch(printMethod)
{
case Screen:
{
cout<<logtxt<<endl;
break;
}
case OneFile:
{
PrintOneFile(LogFile,logtxt);
break;
}
case Classfile:
{
PrintClassfile(level,logtxt);
break;
}
default:
{
break;
}
}
}
void PrintOneFile(const string& logname,const string& logtxt)
{
string _logname=path+logname;
int fd=open(_logname.c_str(),O_WRONLY|O_CREAT|O_APPEND,0666);
if(fd<0)
{
perror("open fail");
return;
}
write(fd,logtxt.c_str(),logtxt.size());
close(fd);
}
void PrintClassfile(int level,const string& logtxt)
{
string filename=LogFile;
filename+='.';
filename+=LevelToString(level);
PrintOneFile(filename,logtxt);
}
void operator()(int level,const char* format,...)
{
time_t t=time(nullptr);
struct tm* ctime=localtime(&t);
char leftbuffer[SIZE];
snprintf(leftbuffer,SIZE,"[%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]={0};
vsnprintf(rightbuffer,SIZE,format,s);
va_end(s);
char logtxt[SIZE*2];
snprintf(logtxt,sizeof(logtxt),"%s %s",leftbuffer,rightbuffer);
printlog(level,logtxt);
}
~Log()
{
}
private:
// 打印方法
int printMethod;
string path;
};
//定义一个全局的log
Log log;
以上就是关于网络版本计算器的全部实现过程了,你学会了吗?如果感觉到有所收获的话,就点点赞点点关注呗,后期还会持续更新网络编程的相关知识哦,我们下期见!!!