C++ 手撸简易服务器
迪丽瓦拉
2024-06-03 10:36:38
0

本文使用上一期写的反射类,另外我发现这个头文件里有RegisterClass 这个结构,还有typedef RegisterClass RegisterClassW这句话。。。这都能重复,汗。

先写个简易的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 
#include 
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\r\n");resp.append("content-language:zh-CN");resp.append("content-type:text/html;charset=utf-8\r\n\r\n");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\r\n");resp.append("Content-Type:text/html\r\n\r\n");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 
#include 
#include 
#include 
#include 
#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 mapTable = {{"/","index"},{"/title","title"}
};
//用来获取url
vector getStringVectorByChar(const string& source, const char& ch) {vector 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 << "接收自客户端数据:\n" << ReceiveBuff << endl;string source(ReceiveBuff);string url = getStringVectorByChar(source, ' ')[1];//反射使用的地方Reflex* factory = Singleton::Instance();CController* a = (CController*)factory->createClass("indexController");string info = "";string req = "";string funName = mapTable[url];a->Call(funName, req, info);//反射使用结束::send(ClientSocket, info.c_str(), info.size(), 0);closesocket(ClientSocket);}
}int main() {//测试反射//Reflex* factory = Singleton::Instance();//CController* a = (CController*)factory->createClass("indexController");//while (1) {//    string funName = "";//    cin >> funName;//    a->Call(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
title

相关内容