这篇文章主要讲解了“基于C++怎么编写一个简单的服务器”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“基于C++怎么编写一个简单的服务器”吧!
先写个简易的controller基类继承反射基类,之后动态调用的时候直接使用父类指针,这样就能根据映射表来动态使用对应的成员方法。
#pragma once #include "Reflex.h" using namespace myUtil; class CController :public RObject{ };
先写个index控制器,这里我是将声明和实现分为两个文件写的,不知道为啥分开写就报错LNK2005 和 LNK1169,好在找到了解决办法,在 属性->配置属性->链接器->命令行中添加 /FORCE:MULTIPLE 即可
这里我给控制器传入的参数是两个字符串,这是简易版本,完全可以照着请求报文和响应报文实现两个类来完成这部分,之后更新吧
接着说,我直接在响应报文中加入了写的对应的两个html页面,之后用Postman来测试
#pragma once #include "CController.h" using namespace std; class indexController : public CController { public: void show(); void fun(); void add(int& a, int& b); void index(const string& req, string& resp); void title(const string& req, string& resp); int m_age; indexController():m_age(10) {} };
#include "indexController.h" #include <iostream> #include <fstream> using namespace std; void indexController::show() { cout << "hello world show" << endl; } void indexController::fun() { cout << "hello world fun" << endl; } void indexController::add(int& a, int& b) { cout << "hello world add" << endl; } void indexController::index(const string& req, string& resp) { resp = ""; resp.append("HTTP/1.1 200 OK "); resp.append("content-language:zh-CN"); resp.append("content-type:text/html;charset=utf-8 "); string text = ""; fstream file; file.open("index.html", ios::in); if (file.fail()) return; while (!file.eof()) { char ch; file.get(ch); text += ch; } resp.append(text); } void indexController::title(const string& req, string& resp) { resp = ""; resp.append("HTTP/1.1 200 OK "); resp.append("Content-Type:text/html "); resp.append("{"name":"title"}"); }
这是一个专门用来注册反射的头文件,在main中直接调用宏即可
#pragma once #include "Reflex.h" #include "indexController.h" #define REFLEX_DECLARE REGISTER_REFLEX(indexController) REGISTER_REFLEX_FIELD(indexController, int, m_age) REGISTER_REFLEX_METHOD(indexController, show) REGISTER_REFLEX_METHOD(indexController, fun) REGISTER_REFLEX_METHOD_ARGS(indexController, add, void, int&, int&) REGISTER_REFLEX_METHOD_ARGS(indexController, index, void, string&, string&) REGISTER_REFLEX_METHOD_ARGS(indexController, title, void, string&, string&)
这里将映射表设置为全局变量,可以将服务作为一个类,在这个类中维护一个注册表,再添加一个方法增加映射,就像springboot中的注释一样,下面有反射的测试,可以用函数名来测试
#include <iostream> #include <string> #include <thread> #include <map> #include <WinSock2.h> #include "Util.h" #include "Singleton.h" #include "macro.h" #include "indexController.h" #pragma comment(lib,"ws2_32.lib") using namespace std; using namespace myUtil; REFLEX_DECLARE //映射表 map<string, string> mapTable = { {"/","index"}, {"/title","title"} }; //用来获取url vector<string> getStringVectorByChar(const string& source, const char& ch) { vector<string> res; string temp = ""; for (char item : source) { if (item == ch) { res.push_back(temp); temp = ""; } else { temp += item; } } if (temp != "") res.push_back(temp); return res; } void threadFunc(SOCKET ServerSocket) { char ReceiveBuff[BUFSIZ]; char SendBuff[BUFSIZ]; while (true) { SOCKET ClientSocket; SOCKADDR_IN ClientAddr; int ClientAddrLen = sizeof(ClientAddr); ClientSocket = ::accept(ServerSocket, (SOCKADDR*)&ClientAddr, &ClientAddrLen); ZeroMemory(ReceiveBuff, BUFSIZ); recv(ClientSocket, ReceiveBuff, BUFSIZ, 0); cout << "接收自客户端数据: " << ReceiveBuff << endl; string source(ReceiveBuff); string url = getStringVectorByChar(source, ' ')[1]; //反射使用的地方 Reflex* factory = Singleton<Reflex>::Instance(); CController* a = (CController*)factory->createClass("indexController"); string info = ""; string req = ""; string funName = mapTable[url]; a->Call<void, string&, string&>(funName, req, info); //反射使用结束 ::send(ClientSocket, info.c_str(), info.size(), 0); closesocket(ClientSocket); } } int main() { //测试反射 //Reflex* factory = Singleton<Reflex>::Instance(); //CController* a = (CController*)factory->createClass("indexController"); //while (1) { // string funName = ""; // cin >> funName; // a->Call<void,int,int>(funName,1,1); //} WORD SocketVersion = MAKEWORD(2, 2); WSADATA wsd; if (WSAStartup(SocketVersion, &wsd) != 0) { cout << "绑定Socket库失败" << endl; } SOCKET ServerSocket; ServerSocket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (ServerSocket == INVALID_SOCKET) { cout << "创建服务器套接字失败" << endl; WSACleanup(); return -1; } SOCKADDR_IN ServerAddr; ServerAddr.sin_family = AF_INET; ServerAddr.sin_port = htons(9090); ServerAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); int RetVal = ::bind(ServerSocket, (SOCKADDR*)&ServerAddr, sizeof(SOCKADDR_IN)); if (RetVal == SOCKET_ERROR) { cout << "套接字绑定失败" << endl; closesocket(ServerSocket); WSACleanup(); return -1; } RetVal = ::listen(ServerSocket, 2); if (RetVal == SOCKET_ERROR) { cout << "套接字监听失败" << endl; closesocket(ServerSocket); WSACleanup(); return -1; } thread th(threadFunc, ServerSocket); th.join(); return 0; }
测试结果
index
title