怎么使用C++实现简易服务器

服务器   发布日期:2023年09月09日   浏览次数:471

今天小编给大家分享一下怎么使用C++实现简易服务器的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

Server.h

  1. #pragma once
  2. #include <string>
  3. #include <iostream>
  4. #include <thread>
  5. #include <unordered_map>
  6. using namespace std;
  7. #ifndef _SERVER_
  8. #define _SERVER_
  9. #include <winsock.h>
  10. #include "Net.h"
  11. #include "Util.h"
  12. #pragma comment(lib,"ws2_32.lib")
  13. NAME_SPACE_START(myUtil)
  14. #define SERVER_ADDR "127.0.0.1"
  15. #define SERVER_PORT 8080
  16. class Server {
  17. public:
  18. Server();
  19. Server(const std::string& addr = SERVER_ADDR, const int& port = SERVER_PORT);
  20. ~Server() {}
  21. public:
  22. bool listen(const int& maxConnect = 1);
  23. void setRoute(const string& url, const string& className, const string& classFunName);
  24. void runRoute(const Request& req, Response* resp);
  25. void setInterceptor(const string& url, const string& InterceptorName);
  26. void close();
  27. protected:
  28. bool Init();
  29. void threadFunc(SOCKET m_server);
  30. int sendTelegram(const SOCKET& accept, const string& info, int flags);
  31. private:
  32. SOCKET m_server;
  33. SOCKADDR_IN m_add_in;
  34. //thread listenThread;
  35. int connectCount{ 0 };
  36. unordered_map<string, pair<string, string>> routeMap;
  37. unordered_map<string, string> interceptorMap;
  38. IniHelper iniHelper;
  39. };
  40. NAME_SPACE_END()
  41. #endif //!_SERVER_

Server.cpp

  1. #include "Server.h"
  2. #include <minwindef.h>
  3. #include <string>
  4. #include <winsock.h>
  5. #include <iostream>
  6. #include <thread>
  7. #include <fstream>
  8. #include "Net.h"
  9. #include "Util.h"
  10. #include "Reflex.h"
  11. #include "CController.h"
  12. #include "Interceptor.h"
  13. using namespace std;
  14. NAME_SPACE_START(myUtil)
  15. Server::Server()
  16. {
  17. m_add_in.sin_family = AF_INET;
  18. m_add_in.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
  19. m_add_in.sin_port = htons(SERVER_PORT);
  20. }
  21. Server::Server(const std::string& addr, const int& port)
  22. {
  23. m_add_in.sin_family = AF_INET;
  24. m_add_in.sin_addr.S_un.S_addr = inet_addr(addr.c_str());
  25. m_add_in.sin_port = htons(port);
  26. }
  27. bool Server::listen(const int& maxConnect)
  28. {
  29. if (!Init()) {
  30. return false;
  31. }
  32. m_server = socket(AF_INET, SOCK_STREAM, 0);
  33. if (::bind(m_server, (sockaddr*)&m_add_in, sizeof(SOCKADDR)) == SOCKET_ERROR) {
  34. WSACleanup();
  35. return false;
  36. }
  37. if (::listen(m_server, maxConnect) < 0) {
  38. WSACleanup();
  39. return false;
  40. }
  41. thread listenThread(&Server::threadFunc, this, m_server);
  42. listenThread.join();
  43. return true;
  44. }
  45. void Server::setRoute(const string& url, const string& className, const string& classFunName)
  46. {
  47. routeMap.insert(pair<string, pair<string, string>>(url, pair<string, string>(className, classFunName)));
  48. }
  49. void Server::runRoute(const Request& req, Response* resp)
  50. {
  51. string url = req.getRequestStatus().Url;
  52. Reflex* factory = myUtil::Singleton<Reflex>::Instance();
  53. string interceptorName = "";
  54. string res = "";
  55. string content = "";
  56. //拦截器
  57. //先去拦截器映射表中寻找类名,没有的话默认使用基类
  58. auto interceptorIt = interceptorMap.find(url);
  59. if (interceptorIt != interceptorMap.end()) interceptorName = interceptorIt->second;
  60. Interceptor* inter = (Interceptor*)factory->createClass(interceptorName);
  61. if (inter == nullptr) inter = new Interceptor();
  62. if (inter->preHandle(req, *resp)) {
  63. //反射
  64. auto it = routeMap.find(url);
  65. if (it != routeMap.end()) {
  66. CController* cont = (CController*)factory->createClass(it->second.first);
  67. res = cont->Call<string, Request, Response*>(it->second.second, req, resp);
  68. }
  69. //反射结束
  70. }
  71. else {
  72. resp->setResponseStatus("HTTP", 1, 1, 404, "Forbidden");
  73. }
  74. if (url.find("favicon.ico") != string::npos) {
  75. content = getFile(iniHelper.getIniConfig("staticResource", "favicon_path", "./favicon.ico"));
  76. resp->setResponseHead("content-type", "image/x-icon");
  77. }
  78. else if(res != "") {
  79. try {
  80. content = getFile(res);
  81. }
  82. catch(exception ex){
  83. content = ex.what();
  84. }
  85. }
  86. resp->setResponseContent(content);
  87. auto list = resp->getCookie();
  88. for (auto item : list) {
  89. resp->setResponseHead("Set-Cookie", item.toString());
  90. }
  91. resp->setResponseHead("content-length", to_string(content.size()));
  92. resp->setResponseHead("Server", "C++MVC");
  93. inter->postHandle(req, *resp);
  94. }
  95. void Server::setInterceptor(const string& url, const string& InterceptorName)
  96. {
  97. interceptorMap.insert(pair<string, string>(url, InterceptorName));
  98. }
  99. void Server::close()
  100. {
  101. closesocket(m_server);
  102. WSACleanup();
  103. }
  104. bool Server::Init()
  105. {
  106. WORD ver = MAKEWORD(2, 2);
  107. WSADATA wsadata;
  108. int errFlag = -1;
  109. errFlag = WSAStartup(ver, &wsadata);
  110. if (errFlag != 0) return false;
  111. //检测版本号
  112. if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wHighVersion) != 2) {
  113. WSACleanup();
  114. return false;
  115. }
  116. return true;
  117. }
  118. void Server::threadFunc(SOCKET m_server)
  119. {
  120. while (1) {
  121. SOCKADDR_IN m_acc_in;
  122. int len = sizeof(SOCKADDR);
  123. SOCKET m_accept = accept(m_server, (sockaddr*)&m_acc_in, &len);
  124. if (m_accept == SOCKET_ERROR) {
  125. continue;
  126. }
  127. int recv_len = 0;
  128. char recv_buf[10000];
  129. recv_len = recv(m_accept, recv_buf, 10000, 0);
  130. //char 转 wchar
  131. int unicodeLen = ::MultiByteToWideChar(CP_UTF8, 0, recv_buf, -1, NULL, 0);
  132. wchar_t* pUnicode = new wchar_t[unicodeLen];
  133. memset(pUnicode, 0, unicodeLen * sizeof(wchar_t));
  134. ::MultiByteToWideChar(CP_UTF8, 0, recv_buf, -1, (LPWSTR)pUnicode, unicodeLen);
  135. wstring rt = pUnicode;
  136. //重设大小
  137. char* pAscii = new char[recv_len];
  138. memset(pAscii, 0, sizeof(char) * recv_len);
  139. strncpy(pAscii, recv_buf, recv_len);
  140. string lrt(pAscii);
  141. //解析请求
  142. Request req(lrt);
  143. Response resp;
  144. runRoute(req, &resp);
  145. cout << "请求地址:" << req.getRequestStatus().Url << endl;
  146. sendTelegram(m_accept, resp.toString(), 0);
  147. closesocket(m_accept);
  148. }
  149. }
  150. int Server::sendTelegram(const SOCKET& accept, const string& info, int flags)
  151. {
  152. int res = send(accept, info.c_str(), info.size(), flags);
  153. return res;
  154. }

NAME_SPACE_END()Interceptor.h

  1. #pragma once
  2. #include "Net.h"
  3. #include "Reflex.h"
  4. using namespace myUtil;
  5. #ifndef _INTERCEPTOR_
  6. #define _INTERCEPTOR_
  7. class Interceptor : public RObject {
  8. public:
  9. virtual bool preHandle(const Request& request, const Response& response) { return true; }
  10. virtual void postHandle(const Request& request, const Response& response) {}
  11. virtual void afterCompletion(const Request& request, const Response& response) {}
  12. };
  13. #endif //!_INTERCEPTOR_

indexInterceptor.h

  1. #pragma once
  2. #include "Interceptor.h"
  3. class IndexInterceptor : public Interceptor {
  4. public:
  5. bool preHandle(const Request& request, const Response& response) override {
  6. return false;
  7. }
  8. void postHandle(const Request& request, const Response& response) override {}
  9. void afterCompletion(const Request& request, const Response& response) override {}
  10. };

InterceptorMacro.h

  1. #pragma once
  2. #include "Reflex.h"
  3. #include "indexInterceptor.h"
  4. #define REFLEX_INPERCEPTOR_DECLARE
  5. REGISTER_REFLEX(IndexInterceptor)

Cookie.h

  1. #pragma once
  2. #ifndef _COOKIE_
  3. #define _COOKIE_
  4. #include <string>
  5. using namespace std;
  6. class Cookie
  7. {
  8. public:
  9. Cookie() {}
  10. Cookie(const string& name, const string& value) :
  11. _name(name), _value(value) {
  12. _comment = "";
  13. _path = "";
  14. _domain = "";
  15. _version = "";
  16. _maxAge = 0;
  17. }
  18. string getNameValue() const;
  19. void setNameValue(const string& name, const string& value);
  20. void setComment(const string& comment);
  21. void setPath(const string& path);
  22. void setDomain(const string& domain);
  23. void setVersion(const string& version);
  24. void setMaxAge(const int& maxAge);
  25. string getComment() const;
  26. string getPath() const;
  27. string getDomain() const;
  28. string getVersion() const;
  29. int getMaxAge() const;
  30. string toString() const;
  31. private:
  32. string _name;
  33. string _value;
  34. //注释
  35. string _comment;
  36. //路径,若要访问的url startwith(path)此cookie携带
  37. string _path;
  38. //网站域名
  39. string _domain;
  40. string _version;
  41. //生存时间
  42. int _maxAge{ 0 };
  43. };
  44. #endif //!_COOKIE_

Cookie.cpp

  1. #include "Cookie.h"
  2. string Cookie::getNameValue() const
  3. {
  4. return _name + "=" + _value;
  5. }
  6. void Cookie::setNameValue(const string& name, const string& value)
  7. {
  8. _name = name;
  9. _value = value;
  10. }
  11. void Cookie::setComment(const string& comment)
  12. {
  13. _comment = comment;
  14. }
  15. void Cookie::setPath(const string& path)
  16. {
  17. _path = path;
  18. }
  19. void Cookie::setDomain(const string& domain)
  20. {
  21. _domain = domain;
  22. }
  23. void Cookie::setVersion(const string& version)
  24. {
  25. _version = version;
  26. }
  27. void Cookie::setMaxAge(const int& maxAge)
  28. {
  29. _maxAge = maxAge;
  30. }
  31. string Cookie::getComment() const
  32. {
  33. return _comment;
  34. }
  35. string Cookie::getPath() const
  36. {
  37. return _path;
  38. }
  39. string Cookie::getDomain() const
  40. {
  41. return _domain;
  42. }
  43. string Cookie::getVersion() const
  44. {
  45. return _version;
  46. }
  47. int Cookie::getMaxAge() const
  48. {
  49. return _maxAge;
  50. }
  51. string Cookie::toString() const
  52. {
  53. string res = getNameValue();
  54. if (_comment != "") res += ";comment=" + _comment;
  55. if (_path != "") res += ";Path=" + _path;
  56. if (_domain != "") res += ";Domain=" + _domain;
  57. if (_version != "") res += ";Version=" + _version;
  58. res += ";Max-Age=" + _maxAge;
  59. return res;
  60. }

CController.h

  1. #pragma once
  2. #ifndef _CCONTROLLER_
  3. #define _CCONTROLLER_
  4. #include "Reflex.h"
  5. using namespace myUtil;
  6. class CController : public RObject
  7. {
  8. };
  9. #endif //!_CCONTROLLER_

indexController.h

  1. #pragma once
  2. #include "CController.h"
  3. #include "Net.h"
  4. #include "Reflex.h"
  5. using namespace myUtil;
  6. class indexController : public CController
  7. {
  8. public:
  9. indexController() {}
  10. ~indexController() {}
  11. string index(const Request& req, Response* resp);
  12. string test(const Request& req, Response* resp);
  13. };

indexController.cpp

  1. #include "indexController.h"
  2. #include <fstream>
  3. using namespace std;
  4. string indexController::index(const Request& req, Response* resp)
  5. {
  6. resp->setResponseStatus("HTTP", 1, 1, 200, "OK");
  7. resp->setResponseHead("Content-Type", "text/html,charset=UTF-8");
  8. return "index.html";
  9. }
  10. string indexController::test(const Request& req, Response* resp)
  11. {
  12. resp->setResponseStatus("HTTP", 1, 1, 200, "OK");
  13. resp->setResponseHead("Content-Type", "text/html,charset=UTF-8");
  14. Cookie cookie("test", "test");
  15. cookie.setDomain("localhost");
  16. cookie.setMaxAge(10);
  17. cookie.setPath("/test");
  18. resp->setCookie(cookie);
  19. return "test.html";
  20. }

ControllerMacro.h

  1. #pragma once
  2. #include "indexController.h"
  3. #define REFLEX_DECLARE
  4. REGISTER_REFLEX(indexController)
  5. REGISTER_REFLEX_METHOD_ARGS(indexController, index, string, Request&, Response*)
  6. REGISTER_REFLEX_METHOD_ARGS(indexController, test, string, Request&, Response*)

Net.h

  1. #pragma once
  2. #ifndef _NET_
  3. #define _NET_
  4. #include <string>
  5. #include <wtypes.h>
  6. #include <unordered_map>
  7. #include "Util.h"
  8. #include "Cookie.h"
  9. using namespace std;
  10. NAME_SPACE_START(myUtil)
  11. #define BLACK "
  12. "
  13. #define SPACE " "
  14. class Net {
  15. public:
  16. virtual string toString() = 0;
  17. virtual vector<Cookie> getCookie() const = 0;
  18. virtual void setCookie(const Cookie& cookie) = 0;
  19. Net() {}
  20. protected:
  21. vector<Cookie> _cookie;
  22. };
  23. struct RequestStatus
  24. {
  25. string RMethod;
  26. string Url;
  27. string ProName;
  28. short verHigh;
  29. short verLow;
  30. };
  31. struct ResponseStatus
  32. {
  33. string ProName;
  34. short verHigh;
  35. short verLow;
  36. short status;
  37. string statusWord;
  38. };
  39. //请求
  40. class Request : public Net {
  41. public:
  42. Request();
  43. Request(const string& sourceStr);
  44. void setRequestStatus(const string& method = "GET", const string& url = "/", const string& _proName = "HTTP", const short& _verHigh = 1, const short& _verLow = 1);
  45. void setRequestHead(const string& headKey, const string& headValue);
  46. void setRequestContent(const string& content);
  47. RequestStatus getRequestStatus() const;
  48. string getRequestContent(const string& headKey) const;
  49. vector<Cookie> getCookie() const override;
  50. void setCookie(const Cookie& cookie) override;
  51. string toString() override;
  52. ~Request() {}
  53. private:
  54. RequestStatus _status;
  55. unordered_map<string, string> _RequestHead;
  56. string _RequestContent{ "" };
  57. };
  58. //响应
  59. //结构 状态行, 响应头部, 空行, 响应正文
  60. class Response : public Net {
  61. public:
  62. Response();
  63. void setResponseStatus(const string& _proName = "HTTP", const short& _verHigh = 1, const short& _verLow = 1, const short& status = 200, const string& word = "");
  64. void setResponseHead(const string& headKey, const string& headValue);
  65. void setResponseContent(const string& content);
  66. ResponseStatus getResponseStatus() const;
  67. string getResponseHeadByKey(const string& headKey) const;
  68. vector<Cookie> getCookie() const override;
  69. void setCookie(const Cookie& cookie) override;
  70. string toString() override;
  71. ~Response();
  72. private:
  73. ResponseStatus _status;
  74. unordered_map<string, string> _ResponseHead;
  75. string _ResponseContent{ "" };
  76. };
  77. class Analyse {
  78. public:
  79. static vector<string> getVectorBySplit(const string& source, const char& ch);
  80. static unordered_map<string, string> getMapBySplit(const string& source, const char& ch2,const char& ch3);
  81. static string makeVectorByChar(const vector<string>& v, const char& ch);
  82. static string makeMapByChars(const unordered_map<string, string>& m, const char& ch2, const char& ch3);
  83. };
  84. NAME_SPACE_END()
  85. #endif //!_NET_

Net.cpp

  1. #include "Net.h"
  2. NAME_SPACE_START(myUtil)
  3. Response::Response()
  4. {
  5. _status.ProName = "HTTP";
  6. _status.verHigh = 1;
  7. _status.verLow = 1;
  8. _status.status = 200;
  9. _status.statusWord = "OK";
  10. }
  11. void Response::setResponseStatus(const string& _proName, const short& _verHigh, const short& _verLow, const short& status, const string& word)
  12. {
  13. _status.ProName = _proName;
  14. _status.verHigh = _verHigh;
  15. _status.verLow = _verLow;
  16. _status.status = status;
  17. _status.statusWord = word;
  18. }
  19. void Response::setResponseHead(const string& headKey, const string& headValue)
  20. {
  21. _ResponseHead.insert(pair<string, string>(headKey, headValue));
  22. }
  23. void Response::setResponseContent(const string& content)
  24. {
  25. _ResponseContent = content;
  26. }
  27. ResponseStatus Response::getResponseStatus() const
  28. {
  29. return _status;
  30. }
  31. string Response::getResponseHeadByKey(const string& headKey) const
  32. {
  33. auto it = _ResponseHead.find(headKey);
  34. if (it == _ResponseHead.end()) return "";
  35. return (*it).second;
  36. }
  37. vector<Cookie> Response::getCookie() const
  38. {
  39. return _cookie;
  40. }
  41. void Response::setCookie(const Cookie& cookie)
  42. {
  43. _cookie.push_back(cookie);
  44. }
  45. string Response::toString()
  46. {
  47. string res = "";
  48. res += _status.ProName + "/" + to_string(_status.verHigh) + "." + to_string(_status.verLow)
  49. + SPACE + to_string(_status.status) + SPACE + _status.statusWord + BLACK;
  50. for (auto it = _ResponseHead.begin(); it != _ResponseHead.end(); it++) {
  51. res += (*it).first + ":" + SPACE + (*it).second + BLACK;
  52. }
  53. res += BLACK;
  54. res += _ResponseContent;
  55. return res;
  56. }
  57. Response::~Response()
  58. {
  59. }
  60. Request::Request(const string& sourceStr)
  61. {
  62. int i = 0;
  63. vector<string> reqGroup = Analyse::getVectorBySplit(sourceStr, '
  64. ');
  65. //解析状态行
  66. vector<string> statuses = Analyse::getVectorBySplit(reqGroup[0], ' ');
  67. _status.RMethod = statuses.at(0);
  68. _status.Url = statuses.at(1);
  69. statuses.at(2).pop_back();
  70. vector<string> verInfo = Analyse::getVectorBySplit(statuses.at(2), '/');
  71. _status.ProName = verInfo.at(0);
  72. _status.verHigh = Analyse::getVectorBySplit(verInfo.at(1), '.').at(0).at(0) - '0';
  73. _status.verLow = Analyse::getVectorBySplit(verInfo.at(1), '.').at(1).at(0) - '0';
  74. //解析请求头
  75. for (i = 1; i < reqGroup.size(); i++) {
  76. if (reqGroup[i] == "
  77. ")break;
  78. reqGroup[i].pop_back();
  79. vector<string> temp = Analyse::getVectorBySplit(reqGroup[i], ':');
  80. _RequestHead.insert(pair<string, string>(temp.at(0), temp.at(1)));
  81. }
  82. i++;
  83. for (i; i < reqGroup.size(); i++) {
  84. _RequestContent += reqGroup.at(i) + "
  85. ";
  86. }
  87. }
  88. void Request::setRequestStatus(const string& method, const string& url, const string& _proName, const short& _verHigh, const short& _verLow)
  89. {
  90. _status.RMethod = method;
  91. _status.Url = url;
  92. _status.ProName = _proName;
  93. _status.verHigh = _verHigh;
  94. _status.verLow = _verLow;
  95. }
  96. void Request::setRequestHead(const string& headKey, const string& headValue)
  97. {
  98. _RequestHead.insert(pair<string, string>(headKey, headValue));
  99. }
  100. void Request::setRequestContent(const string& content)
  101. {
  102. _RequestContent = content;
  103. }
  104. RequestStatus Request::getRequestStatus() const
  105. {
  106. return _status;
  107. }
  108. string Request::getRequestContent(const string& headKey) const
  109. {
  110. return _RequestContent;
  111. }
  112. string Request::toString()
  113. {
  114. string res = "";
  115. res += _status.RMethod + SPACE + _status.Url + SPACE + _status.ProName + "/"
  116. + to_string(_status.verHigh) + "." + to_string(_status.verLow) + BLACK;
  117. for (auto it = _RequestHead.begin(); it != _RequestHead.end(); it++) {
  118. res += (*it).first + ":" + SPACE + (*it).second + BLACK;
  119. }
  120. res += BLACK;
  121. res += _RequestContent;
  122. return res;
  123. }
  124. vector<Cookie> Request::getCookie() const
  125. {
  126. return _cookie;
  127. }
  128. void Request::setCookie(const Cookie& cookie)
  129. {
  130. _cookie.push_back(cookie);
  131. }
  132. vector<string> Analyse::getVectorBySplit(const string& source, const char& ch)
  133. {
  134. vector<string> res;
  135. string temp = "";
  136. for (int i = 0; i < source.size(); i++) {
  137. if (source[i] == ch) {
  138. res.push_back(temp);
  139. temp = "";
  140. }
  141. else {
  142. char ch = source[i];
  143. temp.push_back(ch);
  144. }
  145. }
  146. if (temp != "") res.push_back(temp);
  147. return res;
  148. }
  149. unordered_map<string, string> Analyse::getMapBySplit(const string& source, const char& ch2, const char& ch3)
  150. {
  151. unordered_map<string, string> res;
  152. vector<string> temp = getVectorBySplit(source, ch2);
  153. for (string str : temp) {
  154. vector<string> t = getVectorBySplit(str, ch3);
  155. if (t.size() != 2) continue;
  156. res.insert(pair<string, string>(t.at(0), t.at(1)));
  157. }
  158. return res;
  159. }
  160. string Analyse::makeVectorByChar(const vector<string>& v, const char& ch)
  161. {
  162. string res = "";
  163. for (auto str : v) {
  164. res += str + ch;
  165. }
  166. res.pop_back();
  167. return res;
  168. }
  169. string Analyse::makeMapByChars(const unordered_map<string, string>& m, const char& ch2, const char& ch3)
  170. {
  171. string res = "";
  172. for (auto it = m.begin(); it != m.end(); it++) {
  173. res += it->first + ch3 + it->second + ch2;
  174. }
  175. res.pop_back();
  176. return res;
  177. }
  178. NAME_SPACE_END()

config.ini

  1. [staticResource]
  2. favicon_path=./ico/favicon.ico

使用方式如下

通过setRoute设置路由规则,类似于springboot中的注释部分
通过setInterceptor设置拦截器规则,如果没有设置的话,会默认找基类
以上两个设置之后还要再两个macro文件中设置宏展开,否则反射找不到对应的类

  1. #include <iostream>
  2. #include <string>
  3. #include "ControllerMacro.h"
  4. #include "InterceptorMacro.h"
  5. #include "Server.h"
  6. using namespace std;
  7. using namespace myUtil;
  8. REFLEX_DECLARE
  9. REFLEX_INPERCEPTOR_DECLARE
  10. int main() {
  11. Server server("127.0.0.1", 8080);
  12. server.setRoute("/", "indexController", "index");
  13. server.setRoute("/test", "indexController", "test");
  14. //server.setInterceptor("/test", "IndexInterceptor");
  15. server.listen(2);
  16. return 0;
  17. }

以上就是怎么使用C++实现简易服务器的详细内容,更多关于怎么使用C++实现简易服务器的资料请关注九品源码其它相关文章!