0


C++ 手撸简易服务器(完善版本)

本文没有带反射部分内容,可以看我之前发的

Server.h

#pragmaonce#include<string>#include<iostream>#include<thread>#include<unordered_map>usingnamespace std;#ifndef_SERVER_#define_SERVER_#include<winsock.h>#include"Net.h"#include"Util.h"#pragmacomment(lib,"ws2_32.lib")NAME_SPACE_START(myUtil)#defineSERVER_ADDR"127.0.0.1"#defineSERVER_PORT8080classServer{public:Server();Server(const std::string& addr = SERVER_ADDR,constint& port = SERVER_PORT);~Server(){}public:boollisten(constint& maxConnect =1);voidsetRoute(const string& url,const string& className,const string& classFunName);voidrunRoute(const Request& req, Response* resp);voidsetInterceptor(const string& url,const string& InterceptorName);voidclose();protected:boolInit();voidthreadFunc(SOCKET m_server);intsendTelegram(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"usingnamespace 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,constint& 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);}boolServer::listen(constint& maxConnect){if(!Init()){returnfalse;}
    m_server =socket(AF_INET, SOCK_STREAM,0);if(::bind(m_server,(sockaddr*)&m_add_in,sizeof(SOCKADDR))== SOCKET_ERROR){WSACleanup();returnfalse;}if(::listen(m_server, maxConnect)<0){WSACleanup();returnfalse;}
    thread listenThread(&Server::threadFunc,this, m_server);
    listenThread.join();returntrue;}voidServer::setRoute(const string& url,const string& className,const string& classFunName){
    routeMap.insert(pair<string, pair<string, string>>(url,pair<string, string>(className, classFunName)));}voidServer::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 =newInterceptor();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");}elseif(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);}voidServer::setInterceptor(const string& url,const string& InterceptorName){
    interceptorMap.insert(pair<string, string>(url, InterceptorName));}voidServer::close(){closesocket(m_server);WSACleanup();}boolServer::Init(){
    WORD ver =MAKEWORD(2,2);
    WSADATA wsadata;int errFlag =-1;
    errFlag =WSAStartup(ver,&wsadata);if(errFlag !=0)returnfalse;//检测版本号if(LOBYTE(wsadata.wVersion)!=2||HIBYTE(wsadata.wHighVersion)!=2){WSACleanup();returnfalse;}returntrue;}voidServer::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 转 wcharint  unicodeLen =::MultiByteToWideChar(CP_UTF8,0, recv_buf,-1,NULL,0);wchar_t* pUnicode =newwchar_t[unicodeLen];memset(pUnicode,0, unicodeLen *sizeof(wchar_t));::MultiByteToWideChar(CP_UTF8,0, recv_buf,-1,(LPWSTR)pUnicode, unicodeLen);
        wstring  rt = pUnicode;//重设大小char* pAscii =newchar[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);}}intServer::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

#pragmaonce#include"Net.h"#include"Reflex.h"usingnamespace myUtil;#ifndef_INTERCEPTOR_#define_INTERCEPTOR_classInterceptor:publicRObject{public:virtualboolpreHandle(const Request& request,const Response& response){returntrue;}virtualvoidpostHandle(const Request& request,const Response& response){}virtualvoidafterCompletion(const Request& request,const Response& response){}};#endif//!_INTERCEPTOR_

indexInterceptor.h

#pragmaonce#include"Interceptor.h"classIndexInterceptor:publicInterceptor{public:boolpreHandle(const Request& request,const Response& response)override{returnfalse;}voidpostHandle(const Request& request,const Response& response)override{}voidafterCompletion(const Request& request,const Response& response)override{}};

InterceptorMacro.h

#pragmaonce#include"Reflex.h"#include"indexInterceptor.h"#defineREFLEX_INPERCEPTOR_DECLARE\REGISTER_REFLEX(IndexInterceptor)

Cookie.h

#pragmaonce#ifndef_COOKIE_#define_COOKIE_#include<string>usingnamespace std;classCookie{public:Cookie(){}Cookie(const string& name,const string& value):_name(name),_value(value){
        _comment ="";
        _path ="";
        _domain ="";
        _version ="";
        _maxAge =0;}
    string getNameValue()const;voidsetNameValue(const string& name,const string& value);voidsetComment(const string& comment);voidsetPath(const string& path);voidsetDomain(const string& domain);voidsetVersion(const string& version);voidsetMaxAge(constint& maxAge);
    string getComment()const;
    string getPath()const;
    string getDomain()const;
    string getVersion()const;intgetMaxAge()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;}voidCookie::setNameValue(const string& name,const string& value){
    _name = name;
    _value = value;}voidCookie::setComment(const string& comment){
    _comment = comment;}voidCookie::setPath(const string& path){
    _path = path;}voidCookie::setDomain(const string& domain){
    _domain = domain;}voidCookie::setVersion(const string& version){
    _version = version;}voidCookie::setMaxAge(constint& 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;}intCookie::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

#pragmaonce#ifndef_CCONTROLLER_#define_CCONTROLLER_#include"Reflex.h"usingnamespace myUtil;classCController:publicRObject{};#endif//!_CCONTROLLER_

indexController.h

#pragmaonce#include"CController.h"#include"Net.h"#include"Reflex.h"usingnamespace myUtil;classindexController:publicCController{public:indexController(){}~indexController(){}
    string index(const Request& req, Response* resp);
    string test(const Request& req, Response* resp);};

indexController.cpp

#include"indexController.h"#include<fstream>usingnamespace 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

#pragmaonce#include"indexController.h"#defineREFLEX_DECLARE\REGISTER_REFLEX(indexController)\REGISTER_REFLEX_METHOD_ARGS(indexController, index, string, Request&, Response*)\REGISTER_REFLEX_METHOD_ARGS(indexController, test, string, Request&, Response*)

Net.h

#pragmaonce#ifndef_NET_#define_NET_#include<string>#include<wtypes.h>#include<unordered_map>#include"Util.h"#include"Cookie.h"usingnamespace std;NAME_SPACE_START(myUtil)#defineBLACK"\r\n"#defineSPACE" "classNet{public:virtual string toString()=0;virtual vector<Cookie>getCookie()const=0;virtualvoidsetCookie(const Cookie& cookie)=0;Net(){}protected:
    vector<Cookie> _cookie;};structRequestStatus{
    string RMethod;
    string Url;
    string ProName;short verHigh;short verLow;};structResponseStatus{
    string ProName;short verHigh;short verLow;short status;
    string statusWord;};//请求classRequest:publicNet{public:Request();Request(const string& sourceStr);voidsetRequestStatus(const string& method ="GET",const string& url ="/",const string& _proName ="HTTP",constshort& _verHigh =1,constshort& _verLow =1);voidsetRequestHead(const string& headKey,const string& headValue);voidsetRequestContent(const string& content);

    RequestStatus getRequestStatus()const;
    string getRequestContent(const string& headKey)const;

    vector<Cookie>getCookie()constoverride;voidsetCookie(const Cookie& cookie)override;

    string toString()override;~Request(){}private:
    RequestStatus _status;
    unordered_map<string, string> _RequestHead;
    string _RequestContent{""};};//响应//结构 状态行, 响应头部, 空行, 响应正文classResponse:publicNet{public:Response();voidsetResponseStatus(const string& _proName ="HTTP",constshort& _verHigh =1,constshort& _verLow =1,constshort& status =200,const string& word ="");voidsetResponseHead(const string& headKey,const string& headValue);voidsetResponseContent(const string& content);

    ResponseStatus getResponseStatus()const;
    string getResponseHeadByKey(const string& headKey)const;

    vector<Cookie>getCookie()constoverride;voidsetCookie(const Cookie& cookie)override;

    string toString()override;~Response();private:
    ResponseStatus _status;
    unordered_map<string, string> _ResponseHead;
    string _ResponseContent{""};};classAnalyse{public:static vector<string>getVectorBySplit(const string& source,constchar& ch);static unordered_map<string, string>getMapBySplit(const string& source,constchar& ch1,constchar& ch2);static string makeVectorByChar(const vector<string>& v,constchar& ch);static string makeMapByChars(const unordered_map<string, string>& m,constchar& ch1,constchar& ch2);};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";}voidResponse::setResponseStatus(const string& _proName,constshort& _verHigh,constshort& _verLow,constshort& status,const string& word){
    _status.ProName = _proName;
    _status.verHigh = _verHigh;
    _status.verLow = _verLow;
    _status.status = status;
    _status.statusWord = word;}voidResponse::setResponseHead(const string& headKey,const string& headValue){
    _ResponseHead.insert(pair<string, string>(headKey, headValue));}voidResponse::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;}voidResponse::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,'\n');//解析状态行
    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]=="\r")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)+"\n";}}voidRequest::setRequestStatus(const string& method,const string& url,const string& _proName,constshort& _verHigh,constshort& _verLow){
    _status.RMethod = method;
    _status.Url = url;
    _status.ProName = _proName;
    _status.verHigh = _verHigh;
    _status.verLow = _verLow;}voidRequest::setRequestHead(const string& headKey,const string& headValue){
    _RequestHead.insert(pair<string, string>(headKey, headValue));}voidRequest::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;}voidRequest::setCookie(const Cookie& cookie){
    _cookie.push_back(cookie);}

vector<string>Analyse::getVectorBySplit(const string& source,constchar& 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,constchar& ch1,constchar& ch2){
    unordered_map<string, string> res;
    vector<string> temp =getVectorBySplit(source, ch1);for(string str : temp){
        vector<string> t =getVectorBySplit(str, ch2);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,constchar& ch){
    string res ="";for(auto str : v){
        res += str + ch;}
    res.pop_back();return res;}

string Analyse::makeMapByChars(const unordered_map<string, string>& m,constchar& ch1,constchar& ch2){
    string res ="";for(auto it = m.begin(); it != m.end(); it++){
        res += it->first + ch2 + it->second + ch1;}
    res.pop_back();return res;}NAME_SPACE_END()

config.ini

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

使用方式如下

通过setRoute设置路由规则,类似于springboot中的注释部分
通过setInterceptor设置拦截器规则,如果没有设置的话,会默认找基类
以上两个设置之后还要再两个macro文件中设置宏展开,否则反射找不到对应的类,关于反射如何使用请看这个
https://blog.csdn.net/weixin_43891802/article/details/129411364

#include<iostream>#include<string>#include"ControllerMacro.h"#include"InterceptorMacro.h"#include"Server.h"usingnamespace std;usingnamespace myUtil;

REFLEX_DECLARE
REFLEX_INPERCEPTOR_DECLARE

intmain(){
    Server server("127.0.0.1",8080);
    server.setRoute("/","indexController","index");
    server.setRoute("/test","indexController","test");//server.setInterceptor("/test", "IndexInterceptor");
    server.listen(2);return0;}
标签: c++ 服务器 网络

本文转载自: https://blog.csdn.net/weixin_43891802/article/details/129636049
版权归原作者 咩~~ 所有, 如有侵权,请联系我们删除。

“C++ 手撸简易服务器(完善版本)”的评论:

还没有评论