基于C++編寫一個簡單的服務(wù)器
本文使用上一期寫的反射類,另外我發(fā)現(xiàn)<WinSock2.h>這個頭文件里有RegisterClass 這個結(jié)構(gòu),還有typedef RegisterClass RegisterClassW這句話。。。這都能重復(fù),汗。
先寫個簡易的controller基類繼承反射基類,之后動態(tài)調(diào)用的時候直接使用父類指針,這樣就能根據(jù)映射表來動態(tài)使用對應(yīng)的成員方法。
#pragma once
#include "Reflex.h"
using namespace myUtil;
class CController :public RObject{
};
先寫個index控制器,這里我是將聲明和實(shí)現(xiàn)分為兩個文件寫的,不知道為啥分開寫就報錯LNK2005 和 LNK1169,好在找到了解決辦法,在 屬性->配置屬性->鏈接器->命令行中添加 /FORCE:MULTIPLE 即可
這里我給控制器傳入的參數(shù)是兩個字符串,這是簡易版本,完全可以照著請求報文和響應(yīng)報文實(shí)現(xiàn)兩個類來完成這部分,之后更新吧
接著說,我直接在響應(yīng)報文中加入了寫的對應(yīng)的兩個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\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中直接調(diào)用宏即可
#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&)
這里將映射表設(shè)置為全局變量,可以將服務(wù)作為一個類,在這個類中維護(hù)一個注冊表,再添加一個方法增加映射,就像springboot中的注釋一樣,下面有反射的測試,可以用函數(shù)名來測試
#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 << "接收自客戶端數(shù)據(jù):\n" << 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);
//反射使用結(jié)束
::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 << "創(chuàng)建服務(wù)器套接字失敗" << 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 << "套接字監(jiān)聽失敗" << endl;
closesocket(ServerSocket);
WSACleanup();
return -1;
}
thread th(threadFunc, ServerSocket);
th.join();
return 0;
}測試結(jié)果
index

title

以上就是基于C++編寫一個簡單的服務(wù)器的詳細(xì)內(nèi)容,更多關(guān)于C++服務(wù)器的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Qt5 串口類QSerialPort的實(shí)現(xiàn)
在Qt5以上提供了QtSerialPort模塊,方便編程人員快速的開發(fā)應(yīng)用串口的應(yīng)用程序。本文主要介紹了Qt5 串口類QSerialPort的實(shí)現(xiàn),,感興趣的可以了解一下2022-05-05
C語言中QString與QByteArray互相轉(zhuǎn)換的方法
本文主要介紹了C語言中QString與QByteArray互相轉(zhuǎn)換的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05
C語言字符函數(shù)中的isalnum()和iscntrl()你都知道嗎
這篇文章主要為大家詳細(xì)介紹了C語言字符函數(shù)中的isalnum()和iscntrl(),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-02-02
C++中STL的優(yōu)先隊列priority_queue詳解
這篇文章主要介紹了C++中STL的優(yōu)先隊列priority_queue詳解,今天講一講優(yōu)先隊列(priority_queue),實(shí)際上,它的本質(zhì)就是一個heap,我從STL中扒出了它的實(shí)現(xiàn)代碼,需要的朋友可以參考下2023-08-08

