今天小编给大家分享一下怎么使用C++实现简易服务器的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。
Server.h
#pragma once #include <string> #include <iostream> #include <thread> #include <unordered_map> using namespace std; #ifndef _SERVER_ #define _SERVER_ #include <winsock.h> #include "Net.h" #include "Util.h" #pragma comment(lib,"ws2_32.lib") NAME_SPACE_START(myUtil) #define SERVER_ADDR "127.0.0.1" #define SERVER_PORT 8080 class Server { public: Server(); Server(const std::string& addr = SERVER_ADDR, const int& port = SERVER_PORT); ~Server() {} public: bool listen(const int& maxConnect = 1); void setRoute(const string& url, const string& className, const string& classFunName); void runRoute(const Request& req, Response* resp); void setInterceptor(const string& url, const string& InterceptorName); void close(); protected: bool Init(); void threadFunc(SOCKET m_server); int sendTelegram(const SOCKET& accept, const string& info, int flags); private: SOCKET m_server; SOCKADDR_IN m_add_in; //thread listenThread; int connectCount{ 0 }; unordered_map<string, pair<string, string>> routeMap; unordered_map<string, string> interceptorMap; IniHelper iniHelper; }; NAME_SPACE_END() #endif //!_SERVER_
Server.cpp
#include "Server.h" #include <minwindef.h> #include <string> #include <winsock.h> #include <iostream> #include <thread> #include <fstream> #include "Net.h" #include "Util.h" #include "Reflex.h" #include "CController.h" #include "Interceptor.h" using namespace std; NAME_SPACE_START(myUtil) Server::Server() { m_add_in.sin_family = AF_INET; m_add_in.sin_addr.S_un.S_addr = htonl(INADDR_ANY); m_add_in.sin_port = htons(SERVER_PORT); } Server::Server(const std::string& addr, const int& port) { m_add_in.sin_family = AF_INET; m_add_in.sin_addr.S_un.S_addr = inet_addr(addr.c_str()); m_add_in.sin_port = htons(port); } bool Server::listen(const int& maxConnect) { if (!Init()) { return false; } m_server = socket(AF_INET, SOCK_STREAM, 0); if (::bind(m_server, (sockaddr*)&m_add_in, sizeof(SOCKADDR)) == SOCKET_ERROR) { WSACleanup(); return false; } if (::listen(m_server, maxConnect) < 0) { WSACleanup(); return false; } thread listenThread(&Server::threadFunc, this, m_server); listenThread.join(); return true; } void Server::setRoute(const string& url, const string& className, const string& classFunName) { routeMap.insert(pair<string, pair<string, string>>(url, pair<string, string>(className, classFunName))); } void Server::runRoute(const Request& req, Response* resp) { string url = req.getRequestStatus().Url; Reflex* factory = myUtil::Singleton<Reflex>::Instance(); string interceptorName = ""; string res = ""; string content = ""; //拦截器 //先去拦截器映射表中寻找类名,没有的话默认使用基类 auto interceptorIt = interceptorMap.find(url); if (interceptorIt != interceptorMap.end()) interceptorName = interceptorIt->second; Interceptor* inter = (Interceptor*)factory->createClass(interceptorName); if (inter == nullptr) inter = new Interceptor(); if (inter->preHandle(req, *resp)) { //反射 auto it = routeMap.find(url); if (it != routeMap.end()) { CController* cont = (CController*)factory->createClass(it->second.first); res = cont->Call<string, Request, Response*>(it->second.second, req, resp); } //反射结束 } else { resp->setResponseStatus("HTTP", 1, 1, 404, "Forbidden"); } if (url.find("favicon.ico") != string::npos) { content = getFile(iniHelper.getIniConfig("staticResource", "favicon_path", "./favicon.ico")); resp->setResponseHead("content-type", "image/x-icon"); } else if(res != "") { try { content = getFile(res); } catch(exception ex){ content = ex.what(); } } resp->setResponseContent(content); auto list = resp->getCookie(); for (auto item : list) { resp->setResponseHead("Set-Cookie", item.toString()); } resp->setResponseHead("content-length", to_string(content.size())); resp->setResponseHead("Server", "C++MVC"); inter->postHandle(req, *resp); } void Server::setInterceptor(const string& url, const string& InterceptorName) { interceptorMap.insert(pair<string, string>(url, InterceptorName)); } void Server::close() { closesocket(m_server); WSACleanup(); } bool Server::Init() { WORD ver = MAKEWORD(2, 2); WSADATA wsadata; int errFlag = -1; errFlag = WSAStartup(ver, &wsadata); if (errFlag != 0) return false; //检测版本号 if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wHighVersion) != 2) { WSACleanup(); return false; } return true; } void Server::threadFunc(SOCKET m_server) { while (1) { SOCKADDR_IN m_acc_in; int len = sizeof(SOCKADDR); SOCKET m_accept = accept(m_server, (sockaddr*)&m_acc_in, &len); if (m_accept == SOCKET_ERROR) { continue; } int recv_len = 0; char recv_buf[10000]; recv_len = recv(m_accept, recv_buf, 10000, 0); //char 转 wchar int unicodeLen = ::MultiByteToWideChar(CP_UTF8, 0, recv_buf, -1, NULL, 0); wchar_t* pUnicode = new wchar_t[unicodeLen]; memset(pUnicode, 0, unicodeLen * sizeof(wchar_t)); ::MultiByteToWideChar(CP_UTF8, 0, recv_buf, -1, (LPWSTR)pUnicode, unicodeLen); wstring rt = pUnicode; //重设大小 char* pAscii = new char[recv_len]; memset(pAscii, 0, sizeof(char) * recv_len); strncpy(pAscii, recv_buf, recv_len); string lrt(pAscii); //解析请求 Request req(lrt); Response resp; runRoute(req, &resp); cout << "请求地址:" << req.getRequestStatus().Url << endl; sendTelegram(m_accept, resp.toString(), 0); closesocket(m_accept); } } int Server::sendTelegram(const SOCKET& accept, const string& info, int flags) { int res = send(accept, info.c_str(), info.size(), flags); return res; }
NAME_SPACE_END()Interceptor.h
#pragma once #include "Net.h" #include "Reflex.h" using namespace myUtil; #ifndef _INTERCEPTOR_ #define _INTERCEPTOR_ class Interceptor : public RObject { public: virtual bool preHandle(const Request& request, const Response& response) { return true; } virtual void postHandle(const Request& request, const Response& response) {} virtual void afterCompletion(const Request& request, const Response& response) {} }; #endif //!_INTERCEPTOR_
indexInterceptor.h
#pragma once #include "Interceptor.h" class IndexInterceptor : public Interceptor { public: bool preHandle(const Request& request, const Response& response) override { return false; } void postHandle(const Request& request, const Response& response) override {} void afterCompletion(const Request& request, const Response& response) override {} };
InterceptorMacro.h
#pragma once #include "Reflex.h" #include "indexInterceptor.h" #define REFLEX_INPERCEPTOR_DECLARE REGISTER_REFLEX(IndexInterceptor)
Cookie.h
#pragma once #ifndef _COOKIE_ #define _COOKIE_ #include <string> using namespace std; class Cookie { public: Cookie() {} Cookie(const string& name, const string& value) : _name(name), _value(value) { _comment = ""; _path = ""; _domain = ""; _version = ""; _maxAge = 0; } string getNameValue() const; void setNameValue(const string& name, const string& value); void setComment(const string& comment); void setPath(const string& path); void setDomain(const string& domain); void setVersion(const string& version); void setMaxAge(const int& maxAge); string getComment() const; string getPath() const; string getDomain() const; string getVersion() const; int getMaxAge() const; string toString() const; private: string _name; string _value; //注释 string _comment; //路径,若要访问的url startwith(path)此cookie携带 string _path; //网站域名 string _domain; string _version; //生存时间 int _maxAge{ 0 }; }; #endif //!_COOKIE_
Cookie.cpp
#include "Cookie.h" string Cookie::getNameValue() const { return _name + "=" + _value; } void Cookie::setNameValue(const string& name, const string& value) { _name = name; _value = value; } void Cookie::setComment(const string& comment) { _comment = comment; } void Cookie::setPath(const string& path) { _path = path; } void Cookie::setDomain(const string& domain) { _domain = domain; } void Cookie::setVersion(const string& version) { _version = version; } void Cookie::setMaxAge(const int& maxAge) { _maxAge = maxAge; } string Cookie::getComment() const { return _comment; } string Cookie::getPath() const { return _path; } string Cookie::getDomain() const { return _domain; } string Cookie::getVersion() const { return _version; } int Cookie::getMaxAge() const { return _maxAge; } string Cookie::toString() const { string res = getNameValue(); if (_comment != "") res += ";comment=" + _comment; if (_path != "") res += ";Path=" + _path; if (_domain != "") res += ";Domain=" + _domain; if (_version != "") res += ";Version=" + _version; res += ";Max-Age=" + _maxAge; return res; }
CController.h
#pragma once #ifndef _CCONTROLLER_ #define _CCONTROLLER_ #include "Reflex.h" using namespace myUtil; class CController : public RObject { }; #endif //!_CCONTROLLER_
indexController.h
#pragma once #include "CController.h" #include "Net.h" #include "Reflex.h" using namespace myUtil; class indexController : public CController { public: indexController() {} ~indexController() {} string index(const Request& req, Response* resp); string test(const Request& req, Response* resp); };
indexController.cpp
#include "indexController.h" #include <fstream> using namespace std; string indexController::index(const Request& req, Response* resp) { resp->setResponseStatus("HTTP", 1, 1, 200, "OK"); resp->setResponseHead("Content-Type", "text/html,charset=UTF-8"); return "index.html"; } string indexController::test(const Request& req, Response* resp) { resp->setResponseStatus("HTTP", 1, 1, 200, "OK"); resp->setResponseHead("Content-Type", "text/html,charset=UTF-8"); Cookie cookie("test", "test"); cookie.setDomain("localhost"); cookie.setMaxAge(10); cookie.setPath("/test"); resp->setCookie(cookie); return "test.html"; }
ControllerMacro.h
#pragma once #include "indexController.h" #define REFLEX_DECLARE REGISTER_REFLEX(indexController) REGISTER_REFLEX_METHOD_ARGS(indexController, index, string, Request&, Response*) REGISTER_REFLEX_METHOD_ARGS(indexController, test, string, Request&, Response*)
Net.h
#pragma once #ifndef _NET_ #define _NET_ #include <string> #include <wtypes.h> #include <unordered_map> #include "Util.h" #include "Cookie.h" using namespace std; NAME_SPACE_START(myUtil) #define BLACK " " #define SPACE " " class Net { public: virtual string toString() = 0; virtual vector<Cookie> getCookie() const = 0; virtual void setCookie(const Cookie& cookie) = 0; Net() {} protected: vector<Cookie> _cookie; }; struct RequestStatus { string RMethod; string Url; string ProName; short verHigh; short verLow; }; struct ResponseStatus { string ProName; short verHigh; short verLow; short status; string statusWord; }; //请求 class Request : public Net { public: Request(); Request(const string& sourceStr); void setRequestStatus(const string& method = "GET", const string& url = "/", const string& _proName = "HTTP", const short& _verHigh = 1, const short& _verLow = 1); void setRequestHead(const string& headKey, const string& headValue); void setRequestContent(const string& content); RequestStatus getRequestStatus() const; string getRequestContent(const string& headKey) const; vector<Cookie> getCookie() const override; void setCookie(const Cookie& cookie) override; string toString() override; ~Request() {} private: RequestStatus _status; unordered_map<string, string> _RequestHead; string _RequestContent{ "" }; }; //响应 //结构 状态行, 响应头部, 空行, 响应正文 class Response : public Net { public: Response(); void setResponseStatus(const string& _proName = "HTTP", const short& _verHigh = 1, const short& _verLow = 1, const short& status = 200, const string& word = ""); void setResponseHead(const string& headKey, const string& headValue); void setResponseContent(const string& content); ResponseStatus getResponseStatus() const; string getResponseHeadByKey(const string& headKey) const; vector<Cookie> getCookie() const override; void setCookie(const Cookie& cookie) override; string toString() override; ~Response(); private: ResponseStatus _status; unordered_map<string, string> _ResponseHead; string _ResponseContent{ "" }; }; class Analyse { public: static vector<string> getVectorBySplit(const string& source, const char& ch); static unordered_map<string, string> getMapBySplit(const string& source, const char& ch2,const char& ch3); static string makeVectorByChar(const vector<string>& v, const char& ch); static string makeMapByChars(const unordered_map<string, string>& m, const char& ch2, const char& ch3); }; NAME_SPACE_END() #endif //!_NET_
Net.cpp
#include "Net.h" NAME_SPACE_START(myUtil) Response::Response() { _status.ProName = "HTTP"; _status.verHigh = 1; _status.verLow = 1; _status.status = 200; _status.statusWord = "OK"; } void Response::setResponseStatus(const string& _proName, const short& _verHigh, const short& _verLow, const short& status, const string& word) { _status.ProName = _proName; _status.verHigh = _verHigh; _status.verLow = _verLow; _status.status = status; _status.statusWord = word; } void Response::setResponseHead(const string& headKey, const string& headValue) { _ResponseHead.insert(pair<string, string>(headKey, headValue)); } void Response::setResponseContent(const string& content) { _ResponseContent = content; } ResponseStatus Response::getResponseStatus() const { return _status; } string Response::getResponseHeadByKey(const string& headKey) const { auto it = _ResponseHead.find(headKey); if (it == _ResponseHead.end()) return ""; return (*it).second; } vector<Cookie> Response::getCookie() const { return _cookie; } void Response::setCookie(const Cookie& cookie) { _cookie.push_back(cookie); } string Response::toString() { string res = ""; res += _status.ProName + "/" + to_string(_status.verHigh) + "." + to_string(_status.verLow) + SPACE + to_string(_status.status) + SPACE + _status.statusWord + BLACK; for (auto it = _ResponseHead.begin(); it != _ResponseHead.end(); it++) { res += (*it).first + ":" + SPACE + (*it).second + BLACK; } res += BLACK; res += _ResponseContent; return res; } Response::~Response() { } Request::Request(const string& sourceStr) { int i = 0; vector<string> reqGroup = Analyse::getVectorBySplit(sourceStr, ' '); //解析状态行 vector<string> statuses = Analyse::getVectorBySplit(reqGroup[0], ' '); _status.RMethod = statuses.at(0); _status.Url = statuses.at(1); statuses.at(2).pop_back(); vector<string> verInfo = Analyse::getVectorBySplit(statuses.at(2), '/'); _status.ProName = verInfo.at(0); _status.verHigh = Analyse::getVectorBySplit(verInfo.at(1), '.').at(0).at(0) - '0'; _status.verLow = Analyse::getVectorBySplit(verInfo.at(1), '.').at(1).at(0) - '0'; //解析请求头 for (i = 1; i < reqGroup.size(); i++) { if (reqGroup[i] == " ")break; reqGroup[i].pop_back(); vector<string> temp = Analyse::getVectorBySplit(reqGroup[i], ':'); _RequestHead.insert(pair<string, string>(temp.at(0), temp.at(1))); } i++; for (i; i < reqGroup.size(); i++) { _RequestContent += reqGroup.at(i) + " "; } } void Request::setRequestStatus(const string& method, const string& url, const string& _proName, const short& _verHigh, const short& _verLow) { _status.RMethod = method; _status.Url = url; _status.ProName = _proName; _status.verHigh = _verHigh; _status.verLow = _verLow; } void Request::setRequestHead(const string& headKey, const string& headValue) { _RequestHead.insert(pair<string, string>(headKey, headValue)); } void Request::setRequestContent(const string& content) { _RequestContent = content; } RequestStatus Request::getRequestStatus() const { return _status; } string Request::getRequestContent(const string& headKey) const { return _RequestContent; } string Request::toString() { string res = ""; res += _status.RMethod + SPACE + _status.Url + SPACE + _status.ProName + "/" + to_string(_status.verHigh) + "." + to_string(_status.verLow) + BLACK; for (auto it = _RequestHead.begin(); it != _RequestHead.end(); it++) { res += (*it).first + ":" + SPACE + (*it).second + BLACK; } res += BLACK; res += _RequestContent; return res; } vector<Cookie> Request::getCookie() const { return _cookie; } void Request::setCookie(const Cookie& cookie) { _cookie.push_back(cookie); } vector<string> Analyse::getVectorBySplit(const string& source, const char& ch) { vector<string> res; string temp = ""; for (int i = 0; i < source.size(); i++) { if (source[i] == ch) { res.push_back(temp); temp = ""; } else { char ch = source[i]; temp.push_back(ch); } } if (temp != "") res.push_back(temp); return res; } unordered_map<string, string> Analyse::getMapBySplit(const string& source, const char& ch2, const char& ch3) { unordered_map<string, string> res; vector<string> temp = getVectorBySplit(source, ch2); for (string str : temp) { vector<string> t = getVectorBySplit(str, ch3); if (t.size() != 2) continue; res.insert(pair<string, string>(t.at(0), t.at(1))); } return res; } string Analyse::makeVectorByChar(const vector<string>& v, const char& ch) { string res = ""; for (auto str : v) { res += str + ch; } res.pop_back(); return res; } string Analyse::makeMapByChars(const unordered_map<string, string>& m, const char& ch2, const char& ch3) { string res = ""; for (auto it = m.begin(); it != m.end(); it++) { res += it->first + ch3 + it->second + ch2; } res.pop_back(); return res; } NAME_SPACE_END()
config.ini
[staticResource] favicon_path=./ico/favicon.ico
使用方式如下
通过setRoute设置路由规则,类似于springboot中的注释部分
通过setInterceptor设置拦截器规则,如果没有设置的话,会默认找基类
以上两个设置之后还要再两个macro文件中设置宏展开,否则反射找不到对应的类
#include <iostream> #include <string> #include "ControllerMacro.h" #include "InterceptorMacro.h" #include "Server.h" using namespace std; using namespace myUtil; REFLEX_DECLARE REFLEX_INPERCEPTOR_DECLARE int main() { Server server("127.0.0.1", 8080); server.setRoute("/", "indexController", "index"); server.setRoute("/test", "indexController", "test"); //server.setInterceptor("/test", "IndexInterceptor"); server.listen(2); return 0; }