今天小编给大家分享一下怎么使用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;
}
以上就是怎么使用C++实现简易服务器的详细内容,更多关于怎么使用C++实现简易服务器的资料请关注九品源码其它相关文章!