首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

序列化和反序列化(Linux)

  • 25-04-24 12:01
  • 3251
  • 12780
blog.csdn.net

1 序列化和反序列化

write和read实质是拷贝函数

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

2网络版计算器

2.1代码实现

先把日志拷贝过来

2.1.1必须先要有网络功能

先把 TcpServer.hpp编写号

  1. #pragma once
  2. #include
  3. #include "Socket.hpp"
  4. #include "./logs/ljwlog.h"
  5. class TcpServer
  6. {
  7. public:
  8. TcpServer()
  9. {}
  10. bool InitServer()
  11. {}
  12. void Start()
  13. {}
  14. ~TcpServer()
  15. {}
  16. private:
  17. uint16_t port;
  18. };

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

  1. #pragma once
  2. #include
  3. #include
  4. #include
  5. #include
  6. #include
  7. #include
  8. #include
  9. #include
  10. #include
  11. #include
  12. #include
  13. using namespace std;
  14. class Sock
  15. {
  16. public:
  17. Sock()
  18. {}
  19. ~Sock()
  20. {}
  21. public:
  22. void Socket()//创建套接字的接口
  23. {}
  24. void bind()//绑定的接口
  25. {}
  26. void Listen()//监听状态的接口
  27. {}
  28. int Accept()//获取连接的接口
  29. {}
  30. int Connect()//方便两个客户端和服务器都能使用这个Sock的这个公共方法
  31. {}
  32. private:
  33. int sockfd_;
  34. };

2.1.3 TcpServer.hpp接口的补充

  1. #pragma once
  2. #include
  3. #include "Socket.hpp"
  4. #include "./logs/ljwlog.h"
  5. class TcpServer
  6. {
  7. public:
  8. TcpServer()
  9. {}
  10. bool InitServer()
  11. {
  12. //先创建套接字,再绑定,设置监听状态
  13. listensock_.Socket();
  14. listensock_.bind();
  15. listensock_.Listen();
  16. }
  17. void Start()
  18. {
  19. while(true)
  20. {
  21. int sockfd = listensock_.Accept();
  22. }
  23. }
  24. ~TcpServer()
  25. {}
  26. private:
  27. uint16_t port_;
  28. Sock listensock_; //叫listen套接字,Listen完后有真正的网络文件描述符
  29. };

2.1.4 Sock.hpp接口的补充

  1. #pragma once
  2. #include
  3. #include
  4. #include
  5. #include
  6. #include
  7. #include
  8. #include
  9. #include
  10. #include
  11. #include
  12. #include
  13. #include
  14. #include "./logs/ljwlog.h"
  15. using namespace std;
  16. enum{
  17. SocketErr = 2,
  18. BindErr,
  19. ListenErr
  20. };
  21. const int backlog = 10;
  22. class Sock
  23. {
  24. public:
  25. Sock()
  26. {}
  27. ~Sock()
  28. {}
  29. public:
  30. void Socket()//创建套接字的接口
  31. {
  32. sockfd_ = socket(AF_INET, SOCK_STREAM, 0);//流式套接字 第二个参数是协议类型
  33. if(sockfd_ < 0)
  34. {
  35. FATAL("Socket errno,error:%d,errstring:%s", errno, strerror(errno));
  36. exit(SocketErr);
  37. }
  38. }
  39. void Bind(uint16_t port)//绑定的接口
  40. {
  41. struct sockaddr_in local;
  42. memset(&local, 0, sizeof(local));
  43. local.sin_family = AF_INET;
  44. local.sin_port = htons(port);//主机转网络
  45. local.sin_addr.s_addr = INADDR_ANY;//ip默认0.0.0.0
  46. if(bind(sockfd_, (struct sockaddr*)&local, sizeof(local)) < 0)
  47. {
  48. FATAL("Bind errno,error:%d,errstring:%s", errno, strerror(errno));
  49. exit(BindErr);
  50. }
  51. }
  52. void Listen()//监听状态的接口
  53. {
  54. if(listen(sockfd_, backlog) < 0)
  55. {
  56. FATAL("Listen errno,error:%d,errstring:%s", errno, strerror(errno));
  57. exit(ListenErr);
  58. }
  59. }
  60. // 知道谁链接的我
  61. int Accept(string *clientip, uint16_t *clientport)//获取连接的接口
  62. {
  63. struct sockaddr_in peer;//远端的意思
  64. socklen_t len = sizeof(peer);
  65. int newfd = accept(sockfd_, (struct sockaddr*)&peer, &len);
  66. if(newfd < 0)
  67. {
  68. WARN("accept error, %s: %d", strerror(errno), errno);
  69. return -1;
  70. }
  71. //网络转主机
  72. //拿出客户端的ip和端口号
  73. char ipstr[64];
  74. inet_ntop(AF_INET, &peer.sin_addr, ipstr, sizeof(ipstr));//网络转主机
  75. *clientip = ipstr;//网络转主机
  76. *clientport = ntohs(peer.sin_port);//网络转主机
  77. return newfd;
  78. }
  79. void Close()
  80. {
  81. close(sockfd_);
  82. }
  83. int Connect()//方便两个客户端和服务器都能使用这个Sock的这个公共方法
  84. {
  85. return 0;
  86. }
  87. private:
  88. int sockfd_;
  89. };

2.1.4 TcpServer.hpp提供服务

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

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

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

  1. #pragma once
  2. #include
  3. class Request
  4. {
  5. public:
  6. public:
  7. int x;
  8. int y;
  9. char op;// + - * / %
  10. };
  11. class Response
  12. {
  13. public:
  14. public:
  15. int result;
  16. int code;// 0,可信,否则!0具体是几,表明对应的错误原因
  17. };

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代码
  1. #pragma once
  2. #include
  3. #include
  4. using namespace std;
  5. const string blank_space_sep = " ";//空格分隔符
  6. const string protocol_sep = "\n";//报文分隔符
  7. //序列化和反序列化解决的是对应的是一个报文内部的问题
  8. //还要解决一下报文与报文之间的问题
  9. //封装报头
  10. string Encode(string &content)
  11. {
  12. //封装报头 这里规定的协议就是长度+有效载荷
  13. string package = to_string(content.size());
  14. package += protocol_sep;
  15. package += content;
  16. package += protocol_sep;
  17. return package;
  18. }
  19. //"len"\n"x op y"\n
  20. string Decode(string &package)//将"x op y"提取出来
  21. {
  22. return "";
  23. }
  24. class Request
  25. {
  26. public:
  27. Request(int data1, int data2, char oper): x(data1), y(data2), op(oper)
  28. {}
  29. public:
  30. bool serialization(string *out)
  31. {
  32. //构建报文的有效载荷
  33. //序列化的就是把结构化的(struct)转成string,
  34. // "x op y"
  35. //数字之间是不可能出现分隔符的
  36. string s = to_string(x);
  37. s += blank_space_sep;
  38. s += op;
  39. s += blank_space_sep;
  40. s += to_string(y);
  41. *out = s;
  42. return true;
  43. }
  44. //"x op y" 进行分割
  45. bool deserialization(const string &in)
  46. {
  47. size_t left = in.find(blank_space_sep);
  48. if(left == string::npos) return false;//没找到
  49. string part_x = in.substr(0, left);
  50. size_t right = in.rfind(blank_space_sep);//逆着找
  51. if(right == string::npos) return false;//没找到
  52. string part_y = in.substr(right + 1);
  53. if(left + 2 != right) return false;
  54. op = in[right -1];
  55. x = stoi(part_x);
  56. y = stoi(part_y);
  57. return true;
  58. }
  59. public:
  60. int x;
  61. int y;
  62. char op;// + - * / %
  63. };
  64. class Response
  65. {
  66. public:
  67. Response(int res, int c):result(res), code(c)
  68. {}
  69. public:
  70. //序列化是结构体转字符串的
  71. bool serialization(string *out)
  72. {
  73. // 序列化成这样"result code"
  74. //构建报文的有效载荷
  75. string s = to_string(result);
  76. s += blank_space_sep;
  77. s += to_string(code);
  78. *out = s;
  79. return true;
  80. }
  81. //反序列化 一定是你要传过来一个字符串
  82. bool deserialization(const string &in) //"result code" 协议定制好了就必须是这个样子
  83. {
  84. size_t pos = in.find(blank_space_sep);
  85. if(pos == string::npos) return false;//没找到
  86. string part_left = in.substr(0, pos);
  87. string part_right = in.substr(pos + 1);
  88. result = stoi(part_left);
  89. code = stoi(part_right);
  90. return true;
  91. }
  92. public:
  93. int result;
  94. int code;// 0,可信,否则!0具体是几,表明对应的错误原因
  95. };
2.1.6.6 测试一下序列化和添加报头
  1. #include
  2. #include "TcpServer.hpp"
  3. #include "Protocol.hpp"
  4. using namespace std;
  5. int main()
  6. {
  7. Request req(123, 456, '+');
  8. string s;
  9. req.serialization(&s);//序列化
  10. cout << s << endl;
  11. s = Encode(s);//给s报文添加报头
  12. cout << s ;//这是网络里发的样子
  13. return 0;
  14. }

2.1.6.7 测试一下拿到报文的内容
  1. #include
  2. #include "TcpServer.hpp"
  3. #include "Protocol.hpp"
  4. using namespace std;
  5. int main()
  6. {
  7. Request req(123, 456, '+');
  8. string s;
  9. req.serialization(&s);//序列化
  10. //cout << s << endl;
  11. s = Encode(s);//给s报文添加报头
  12. cout << s ;//这是网络里发的样子
  13. //拿到报文的内容
  14. string content;
  15. bool r = Decode(s, &content);
  16. cout<< content <
  17. return 0;
  18. }

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

  1. #pragma once
  2. #include
  3. #include
  4. #include "Protocol.hpp"
  5. using namespace std;
  6. //如何处理整个报文
  7. //把协议和网络功能组合在一起 然后再把这个头文件"ServerCal.hpp"交给ServerCal.cc
  8. class ServerCal
  9. {
  10. public:
  11. ServerCal()
  12. {}
  13. Response CalculatorHelper(const Request &req)
  14. {
  15. Response resp(0, 0);
  16. switch(req.op)
  17. {
  18. case '+':
  19. resp.result = req.x + req.y;
  20. case '-':
  21. resp.result = req.x - req.y;
  22. case '*':
  23. resp.result = req.x * req.y;
  24. case '/':
  25. resp.result = req.x / req.y;
  26. }
  27. return resp;
  28. }
  29. //提供一个网络计算服务 把先把报文给我
  30. string Calculator(string &package)//肯定是收到一个序列化的请求报文
  31. {
  32. //收到一个请求报文 添加报头
  33. string content;
  34. bool r = Decode(package, &content);
  35. //报文不完整就直接返回
  36. if(!r) return;
  37. //完整的报文
  38. //请求的对象
  39. Request req;
  40. //反序列化
  41. r = req.deserialization(content);
  42. if(!r) return;
  43. //结果
  44. Response resp = CalculatorHelper(req);
  45. //返回结果
  46. //序列化
  47. string s;
  48. resp.serialization(&s);
  49. //序列化后,想把它当作网络报文发出去
  50. //添加报头
  51. s = Encode(s);
  52. return s;
  53. }
  54. ~ServerCal()
  55. {}
  56. };
2.1.7.3 完善一下TcpServer.hpp

2.1.7.4 测试

2.1.7.5 完善一下ClientCal.cc

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

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

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

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

没有bind 也就没有listen了

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

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

  1. #include
  2. #include
  3. #include
  4. #include
  5. #include "Socket.hpp"
  6. #include "Protocol.hpp"
  7. using namespace std;
  8. void Usage(const string &proc)
  9. {
  10. cout << "\nUsage" << proc << " serverip serverport\n\n"
  11. << endl;
  12. }
  13. //./clientcal serverip serverport
  14. int main(int argc, char *argv[])
  15. {
  16. if (argc != 3)
  17. {
  18. Usage(argv[0]);
  19. exit(0);
  20. }
  21. string serverip = argv[1];
  22. uint16_t serverport = stoi(argv[2]);
  23. Sock sockfd;
  24. sockfd.Socket();
  25. bool r = sockfd.Connect(serverip, serverport);
  26. if (!r)
  27. return 1;
  28. srand(time(nullptr));
  29. const string s = "+-*/^!~";
  30. int cnt = 10;
  31. string inbuffer_stream;
  32. while (cnt--)
  33. {
  34. cout<< "第" <"次测试..." <
  35. int x = rand() % 100 + 1;
  36. usleep(1234);
  37. int y = rand() % 100 + 1;
  38. usleep(4321);
  39. char op = s[rand() % s.size()];
  40. Request req(x, y, op);
  41. req.DebugPrint();
  42. // 根据协议把请求发给服务器,Request是一个结构化的数据,发不了
  43. // 先序列化得到对应的字符串
  44. string package;
  45. req.serialization(&package);
  46. // 还是不能往网络里发送 添加报头还要
  47. //"len"\n"x op y"\n
  48. package = Encode(package);
  49. cout << "这是最新的发出去的请求:\n"
  50. << package;
  51. // 把请求往服务器端写
  52. write(sockfd.Fd(), package.c_str(), package.size());
  53. cout<
  54. // 接收服务器发回来的信息
  55. char buffer[128];
  56. //我们也没法保证我们能够读到一个完整的报文
  57. ssize_t n = read(sockfd.Fd(), buffer, sizeof(buffer));
  58. if (n > 0)
  59. {
  60. buffer[n] = 0;
  61. inbuffer_stream += buffer;// "len"\n"result code"\n
  62. string content;
  63. //解码
  64. bool r = Decode(inbuffer_stream, &content);//"result code"
  65. assert(r);
  66. //反序列化
  67. Response resp;
  68. r = resp.deserialization(content);
  69. assert(r);
  70. resp.DebugPrint();
  71. }
  72. sleep(1);
  73. }
  74. sockfd.Close();
  75. return 0;
  76. }

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的用法
  1. #include
  2. #include "jsoncpp/json/json.h"
  3. using namespace std;
  4. int main()
  5. {
  6. Json::Value root;
  7. root["x"] = 100;
  8. root["y"] = 100;
  9. root["op"] = '+';
  10. //描述
  11. root["dect"] = "this is a + oper";
  12. //比较快的序列化
  13. Json::FastWriter w;
  14. string res = w.write(root);
  15. cout<< res <
  16. return 0;
  17. }

编译时要带-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

  1. #include
  2. #include
  3. #include
  4. #include
  5. #include "Socket.hpp"
  6. #include "Protocol.hpp"
  7. using namespace std;
  8. void Usage(const string &proc)
  9. {
  10. cout << "\nUsage" << proc << " serverip serverport\n\n"
  11. << endl;
  12. }
  13. //./clientcal serverip serverport
  14. int main(int argc, char *argv[])
  15. {
  16. if (argc != 3)
  17. {
  18. Usage(argv[0]);
  19. exit(0);
  20. }
  21. string serverip = argv[1];
  22. uint16_t serverport = stoi(argv[2]);
  23. Sock sockfd;
  24. sockfd.Socket();
  25. bool r = sockfd.Connect(serverip, serverport);
  26. if (!r)
  27. return 1;
  28. srand(time(nullptr));
  29. const string s = "+-*/^!~";
  30. int cnt = 10;
  31. string inbuffer_stream;
  32. while (cnt--)
  33. {
  34. cout<< "第" <"次测试..." <
  35. int x = rand() % 100 + 1;
  36. usleep(1234);
  37. int y = rand() % 100 + 1;
  38. usleep(4321);
  39. char op = s[rand() % s.size()];
  40. Request req(x, y, op);
  41. req.DebugPrint();
  42. // 根据协议把请求发给服务器,Request是一个结构化的数据,发不了
  43. // 先序列化得到对应的字符串
  44. string package;
  45. req.serialization(&package);
  46. // 还是不能往网络里发送 添加报头还要
  47. //"len"\n"x op y"\n
  48. package = Encode(package);
  49. cout << "这是最新的发出去的请求:\n"
  50. << package;
  51. // 把请求往服务器端写
  52. write(sockfd.Fd(), package.c_str(), package.size());
  53. // write(sockfd.Fd(), package.c_str(), package.size());
  54. // write(sockfd.Fd(), package.c_str(), package.size());
  55. // write(sockfd.Fd(), package.c_str(), package.size());
  56. // write(sockfd.Fd(), package.c_str(), package.size());
  57. // write(sockfd.Fd(), package.c_str(), package.size());
  58. cout<
  59. // 接收服务器发回来的信息
  60. char buffer[128];
  61. //我们也没法保证我们能够读到一个完整的报文
  62. ssize_t n = read(sockfd.Fd(), buffer, sizeof(buffer));
  63. if (n > 0)
  64. {
  65. buffer[n] = 0;
  66. inbuffer_stream += buffer;// "len"\n"result code"\n
  67. cout<< inbuffer_stream <
  68. string content;
  69. //解码
  70. bool r = Decode(inbuffer_stream, &content);//"result code"
  71. assert(r);
  72. //反序列化
  73. Response resp;
  74. r = resp.deserialization(content);
  75. assert(r);
  76. resp.DebugPrint();
  77. }
  78. sleep(1);
  79. }
  80. sockfd.Close();
  81. return 0;
  82. }

4.2 makefile

  1. .PHONY:all
  2. all:servercal clientcal
  3. servercal:ServerCal.cc
  4. g++ -g -o $@ $^ -lpthread -std=c++11 -ljsoncpp
  5. clientcal:ClientCal.cc
  6. g++ -o $@ $^ -lpthread -std=c++11 -ljsoncpp
  7. .PHONT:clean
  8. clean:
  9. rm -f clientcal servercal

4.3 Protocol.hpp

  1. #pragma once
  2. #include
  3. #include
  4. #include "jsoncpp/json/json.h"
  5. using namespace std;
  6. const string blank_space_sep = " ";//空格分隔符
  7. const string protocol_sep = "\n";//报文分隔符
  8. //序列化和反序列化解决的是对应的是一个报文内部的问题
  9. //还要解决一下报文与报文之间的问题
  10. //添加报头 "len"\n"x op y"\n
  11. string Encode(string &content)
  12. {
  13. //封装报头 这里规定的协议就是长度+有效载荷
  14. string package = to_string(content.size());
  15. package += protocol_sep;
  16. package += content;
  17. package += protocol_sep;
  18. return package;
  19. }
  20. //将"x op y"提取出来 有效载荷
  21. //"len"\n"x op y"\n package整个报文 *content把结果带出去
  22. bool Decode(string &package, string *content)
  23. {
  24. size_t pos = package.find(protocol_sep);
  25. if(pos == string::npos) return false;
  26. string len_str = package.substr(0, pos);
  27. size_t len = stoi(len_str); //拿到了len长度
  28. //判断一下package的长度够不够
  29. //package = len_str + content_str + 2
  30. size_t total_len = len_str.size() + len + 2;
  31. if(package.size() < total_len) return false;
  32. //大于没事,因为肯定有完整的报文
  33. //*content把结果带出去 "x op y"
  34. *content = package.substr(pos + 1, len);
  35. // earse 移除报文
  36. package.erase(0, total_len);
  37. return true;
  38. }
  39. class Request
  40. {
  41. public:
  42. Request(int data1, int data2, char oper): x(data1), y(data2), op(oper)
  43. {}
  44. Request()
  45. {}
  46. public:
  47. bool serialization(string *out)
  48. {
  49. // //构建报文的有效载荷
  50. // //序列化的就是把结构化的(struct)转成string,
  51. // // "x op y"
  52. // //数字之间是不可能出现分隔符的
  53. // string s = to_string(x);
  54. // s += blank_space_sep;
  55. // s += op;
  56. // s += blank_space_sep;
  57. // s += to_string(y);
  58. // *out = s;
  59. // return true;
  60. //Json 序列化
  61. Json::Value root;
  62. root["x"] = x;
  63. root["y"] = y;
  64. root["op"] = op;
  65. Json::FastWriter w;
  66. *out = w.write(root);
  67. return true;
  68. }
  69. //"x op y" 进行分割
  70. bool deserialization(const string &in)
  71. {
  72. // size_t left = in.find(blank_space_sep);
  73. // if(left == string::npos) return false;//没找到
  74. // string part_x = in.substr(0, left);
  75. // size_t right = in.rfind(blank_space_sep);//逆着找
  76. // if(right == string::npos) return false;//没找到
  77. // string part_y = in.substr(right + 1);
  78. // if(left + 2 != right) return false;
  79. // op = in[right -1];
  80. // x = stoi(part_x);
  81. // y = stoi(part_y);
  82. // return true;
  83. //Json 反序列化
  84. Json::Value root;
  85. Json::Reader r;
  86. r.parse(in, root);
  87. //反序列化到root
  88. //提取出来
  89. x = root["x"].asInt();
  90. y = root["y"].asInt();
  91. op = root["op"].asInt();
  92. return true;
  93. }
  94. void DebugPrint()
  95. {
  96. cout<< "新请求构建完成" << x << op << y << "=?" <
  97. }
  98. public:
  99. int x;
  100. int y;
  101. char op;// + - * / %
  102. };
  103. class Response
  104. {
  105. public:
  106. Response(int res, int c):result(res), code(c)
  107. {}
  108. Response()
  109. {}
  110. public:
  111. //序列化是结构体转字符串的
  112. bool serialization(string *out)
  113. {
  114. // // 序列化成这样"result code"
  115. // //构建报文的有效载荷
  116. // string s = to_string(result);
  117. // s += blank_space_sep;
  118. // s += to_string(code);
  119. // *out = s;
  120. // return true;
  121. //Json 序列化
  122. Json::Value root;
  123. root["result"] = result;
  124. root["code"] = code;
  125. Json::FastWriter w;
  126. *out = w.write(root);
  127. return true;
  128. }
  129. //反序列化 一定是你要传过来一个字符串
  130. bool deserialization(const string &in) //"result code" 协议定制好了就必须是这个样子
  131. {
  132. // size_t pos = in.find(blank_space_sep);
  133. // if(pos == string::npos) return false;//没找到
  134. // string part_left = in.substr(0, pos);
  135. // string part_right = in.substr(pos + 1);
  136. // result = stoi(part_left);
  137. // code = stoi(part_right);
  138. // return true;
  139. //Json 反序列化
  140. Json::Value root;
  141. Json::Reader r;
  142. r.parse(in, root);
  143. //反序列化到root
  144. //提取出来
  145. result = root["result"].asInt();
  146. code = root["code"].asInt();
  147. return true;
  148. }
  149. void DebugPrint()
  150. {
  151. cout<< "响应结果完成" << "result:"<< result <<"code:" <
  152. }
  153. public:
  154. int result;
  155. int code;// 0,可信,否则!0具体是几,表明对应的错误原因
  156. };

4.4 ServerCal.cc

  1. #include
  2. #include
  3. #include "TcpServer.hpp"
  4. #include "Protocol.hpp"
  5. #include "ServerCal.hpp"
  6. using namespace std;
  7. void Usage(const string& proc)
  8. {
  9. cout<<"\nUsage" << proc << "port\n\n" <
  10. }
  11. int main(int argc, char* argv[])
  12. {
  13. if(argc != 2)
  14. {
  15. Usage(argv[0]);
  16. exit(0);
  17. }
  18. uint16_t port = stoi(argv[1]);
  19. ServerCal cal;
  20. TcpServer *tsvp = new TcpServer(port, bind(&ServerCal::Calculator, &cal, placeholders::_1));
  21. tsvp->InitServer();
  22. daemon(0, 0);
  23. tsvp->Start();
  24. // Response resp(1000, 0);
  25. // //发回去
  26. // string content;
  27. // resp.serialization(&content);
  28. // //cout << content << endl;
  29. // //要往网络里发 先添加报头
  30. // string package = Encode(content);
  31. // cout << package << endl;
  32. // //解码 放进s
  33. // string s;
  34. // bool r = Decode(package, &s);
  35. // cout<< s <
  36. // //反序列化 打散成对象
  37. // Response temp;
  38. // temp.deserialization(s);
  39. // cout<<"\n\n";
  40. // cout<< temp.result <
  41. // cout<< temp.code << endl;
  42. // Request req(123, 456, '+');
  43. // string s;
  44. // req.serialization(&s);//序列化
  45. // //cout << s << endl;
  46. // s = Encode(s);//给s报文添加报头
  47. // cout << s ;//这是网络里发的样子
  48. // //拿到报文的内容
  49. // string content;
  50. // bool r = Decode(s, &content);
  51. // cout<< content <
  52. // //对收到报文进行反序列化 打散成对象
  53. // Request temp;
  54. // temp.deserialization(content);
  55. // cout<< temp.x <
  56. return 0;
  57. }

4.5 ServerCal.hpp

  1. #pragma once
  2. #include
  3. #include
  4. #include "Protocol.hpp"
  5. using namespace std;
  6. //如何处理整个报文
  7. //把协议和网络功能组合在一起 然后再把这个头文件"ServerCal.hpp"交给ServerCal.cc
  8. class ServerCal
  9. {
  10. public:
  11. ServerCal()
  12. {}
  13. Response CalculatorHelper(const Request &req)
  14. {
  15. Response resp(0, 0);
  16. switch(req.op)
  17. {
  18. case '+':
  19. resp.result = req.x + req.y;
  20. break;
  21. case '-':
  22. resp.result = req.x - req.y;
  23. break;
  24. case '*':
  25. resp.result = req.x * req.y;
  26. break;
  27. case '/':
  28. if(req.y == 0) resp.code = 1;
  29. else
  30. {
  31. resp.result = req.x / req.y;
  32. }
  33. break;
  34. default:
  35. resp.code = 2;
  36. break;
  37. }
  38. return resp;
  39. }
  40. //提供一个网络计算服务 把先把报文给我
  41. // package: "len"\n"10 + 20"\n
  42. string Calculator(string &package)//肯定是收到一个序列化的请求报文
  43. {
  44. //收到一个请求报文 添加报头
  45. string content;
  46. bool r = Decode(package, &content);
  47. //报文不完整就直接返回
  48. if(!r) return "";
  49. //完整的报文
  50. //请求的对象
  51. Request req;
  52. //反序列化
  53. r = req.deserialization(content);
  54. if(!r) return "";
  55. //结果
  56. Response resp = CalculatorHelper(req);
  57. //返回结果
  58. //序列化
  59. string s;
  60. resp.serialization(&s);
  61. //序列化后,想把它当作网络报文发出去
  62. //添加报头
  63. s = Encode(s);
  64. return s;
  65. }
  66. ~ServerCal()
  67. {}
  68. };

4.6 Socket.hpp

  1. #pragma once
  2. #include
  3. #include
  4. #include
  5. #include
  6. #include
  7. #include
  8. #include
  9. #include
  10. #include
  11. #include
  12. #include
  13. #include
  14. #include "./logs/ljwlog.h"
  15. using namespace std;
  16. enum
  17. {
  18. SocketErr = 2,
  19. BindErr,
  20. ListenErr
  21. };
  22. const int backlog = 10;
  23. class Sock
  24. {
  25. public:
  26. Sock()
  27. {
  28. }
  29. ~Sock()
  30. {
  31. }
  32. public:
  33. void Socket() // 创建套接字的接口
  34. {
  35. sockfd_ = socket(AF_INET, SOCK_STREAM, 0); // 流式套接字 第二个参数是协议类型
  36. if (sockfd_ < 0)
  37. {
  38. FATAL("Socket errno,error:%d,errstring:%s", errno, strerror(errno));
  39. exit(SocketErr);
  40. }
  41. }
  42. void Bind(uint16_t port) // 绑定的接口
  43. {
  44. struct sockaddr_in local;
  45. memset(&local, 0, sizeof(local));
  46. local.sin_family = AF_INET;
  47. local.sin_port = htons(port); // 主机转网络
  48. local.sin_addr.s_addr = INADDR_ANY; // ip默认0.0.0.0
  49. if (bind(sockfd_, (struct sockaddr *)&local, sizeof(local)) < 0)
  50. {
  51. FATAL("Bind errno,error:%d,errstring:%s", errno, strerror(errno));
  52. exit(BindErr);
  53. }
  54. }
  55. void Listen() // 监听状态的接口
  56. {
  57. if (listen(sockfd_, backlog) < 0)
  58. {
  59. FATAL("Listen errno,error:%d,errstring:%s", errno, strerror(errno));
  60. exit(ListenErr);
  61. }
  62. }
  63. // 知道谁链接的我
  64. int Accept(string *clientip, uint16_t *clientport) // 获取连接的接口
  65. {
  66. struct sockaddr_in peer; // 远端的意思
  67. socklen_t len = sizeof(peer);
  68. int newfd = accept(sockfd_, (struct sockaddr *)&peer, &len);
  69. if (newfd < 0)
  70. {
  71. WARN("accept error, %s: %d", strerror(errno), errno);
  72. return -1;
  73. }
  74. // 网络转主机
  75. // 拿出客户端的ip和端口号
  76. char ipstr[64];
  77. inet_ntop(AF_INET, &peer.sin_addr, ipstr, sizeof(ipstr)); // 网络转主机
  78. *clientip = ipstr; // 网络转主机
  79. *clientport = ntohs(peer.sin_port); // 网络转主机
  80. return newfd;
  81. }
  82. void Close()
  83. {
  84. close(sockfd_);
  85. }
  86. int Connect(const string &ip, const uint16_t &port) // 方便两个客户端和服务器都能使用这个Sock的这个公共方法
  87. {
  88. struct sockaddr_in peer;
  89. memset(&peer, 0, sizeof(peer));
  90. peer.sin_family = AF_INET;
  91. peer.sin_port = htons(port);
  92. inet_pton(AF_INET, ip.c_str(), &(peer.sin_addr));
  93. int n = connect(sockfd_, (struct sockaddr *)&peer, sizeof(peer));
  94. if (n == -1)
  95. {
  96. cerr << "connect to" << ip << "::" << port <<"error"<< endl;
  97. return false;
  98. }
  99. return true;
  100. }
  101. int Fd()
  102. {
  103. return sockfd_;
  104. }
  105. private:
  106. int sockfd_;
  107. };

4.7 TcpServer.hpp

  1. #pragma once
  2. #include
  3. #include
  4. #include
  5. #include "Socket.hpp"
  6. #include "./logs/ljwlog.h"
  7. // 返回值 参数
  8. using fun_t = function< string(string &package)>;
  9. class TcpServer
  10. {
  11. public:
  12. TcpServer(uint16_t port, fun_t callback):port_(port), callback_(callback)
  13. {}
  14. bool InitServer( )
  15. {
  16. //先创建套接字,再绑定,设置监听状态
  17. listensock_.Socket();
  18. listensock_.Bind(port_);
  19. listensock_.Listen();
  20. INFO("init server");
  21. return true;
  22. }
  23. void Start()
  24. {
  25. signal(SIGCHLD, SIG_IGN);//忽略就不用等待了
  26. signal(SIGPIPE, SIG_IGN);//忽略就不用等待了
  27. while(true)
  28. {
  29. string clientip;
  30. uint16_t clientport;
  31. int sockfd = listensock_.Accept(&clientip, &clientport);
  32. if(sockfd < 0) continue;
  33. INFO("Accept server sockfd:%d clientip:%s clientport:%d", sockfd, clientip.c_str(), clientport);
  34. //提供服务
  35. if(fork() == 0)
  36. {
  37. //子进程
  38. listensock_.Close();
  39. //请求的信息流
  40. string inbuffer_stream;
  41. //数据计算
  42. while(true)
  43. {
  44. //从网络当中读数据到buffer当中
  45. char buffer[1024];
  46. ssize_t n = read(sockfd, buffer, sizeof(buffer));
  47. if(n > 0)
  48. {
  49. buffer[n] = 0;
  50. inbuffer_stream += buffer;
  51. DEBUG("inbuffer_stream: %s", inbuffer_stream.c_str());
  52. while(true)
  53. {
  54. string info = callback_(inbuffer_stream);
  55. //如果没有读到完整的报文,就会返回一个空串infp
  56. if(info.empty()) break;
  57. write(sockfd, info.c_str(), info.size());
  58. }
  59. }
  60. else if(n == 0) break;
  61. else break;
  62. }
  63. exit(0);
  64. }
  65. close(sockfd);//不用等了直接关就好了
  66. }
  67. }
  68. ~TcpServer()
  69. {}
  70. private:
  71. uint16_t port_;
  72. Sock listensock_; //叫listen套接字,Listen完后有真正的网络文件描述符
  73. fun_t callback_;
  74. };

注:本文转载自blog.csdn.net的Ljw...的文章"https://blog.csdn.net/2401_83427936/article/details/144003486"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

122
操作系统
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2024 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top