服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C/C++ - 基于C++编写一个简单的服务器

基于C++编写一个简单的服务器

2023-03-16 14:59咩~~ C/C++

这篇文章主要为大家详细介绍了如何基于C++编写一个简单的服务器,文中的示例代码讲解详细,具有一定的参考价值,感兴趣的小伙伴可以了解一下

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

先写个简易的controller基类继承反射基类,之后动态调用的时候直接使用父类指针,这样就能根据映射表来动态使用对应的成员方法。

?
1
2
3
4
5
#pragma once
#include "Reflex.h"
using namespace myUtil;
class CController :public RObject{
};

先写个index控制器,这里我是将声明和实现分为两个文件写的,不知道为啥分开写就报错LNK2005 和 LNK1169,好在找到了解决办法,在 属性->配置属性->链接器->命令行中添加 /FORCE:MULTIPLE 即可

这里我给控制器传入的参数是两个字符串,这是简易版本,完全可以照着请求报文和响应报文实现两个类来完成这部分,之后更新吧
接着说,我直接在响应报文中加入了写的对应的两个html页面,之后用Postman来测试

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#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) {}
};
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#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中直接调用宏即可

?
1
2
3
4
5
6
7
8
9
10
11
#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中的注释一样,下面有反射的测试,可以用函数名来测试

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#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 << "接收自客户端数据:\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);
        //反射使用结束
        ::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

基于C++编写一个简单的服务器

title

基于C++编写一个简单的服务器

以上就是基于C++编写一个简单的服务器的详细内容,更多关于C++服务器的资料请关注服务器之家其它相关文章!

原文链接:https://blog.csdn.net/weixin_43891802/article/details/129516506

延伸 · 阅读

精彩推荐
  • C/C++OpenCV 图像金字塔的实现示例

    OpenCV 图像金字塔的实现示例

    本文将结合实例代码,介绍OpenCV 图像金字塔,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...

    qq_423441328512021-11-19
  • C/C++提高C程序效率的10种有效方法

    提高C程序效率的10种有效方法

    本文向你介绍规范你的C代码的10种方法。需要的朋友可以过来参考下,希望对大家有所帮助...

    c语言程序设计4862021-01-06
  • C/C++关于STL中的map容器的一些总结

    关于STL中的map容器的一些总结

    对于map的学习,或者说是对STL中的容器的学习,要知道每种容器的实现原理,每种适合适合解决什么问题的,才是关键...

    C语言教程网10912020-12-31
  • C/C++C++常量详解二(常量形参,常量返回值,常量成员函数)

    C++常量详解二(常量形参,常量返回值,常量成员函数)

    这篇文章主要介绍了C++常量详解二(常量形参,常量返回值,常量成员函数),需要的朋友可以参考下...

    Jang19964772021-05-14
  • C/C++C++中链表操作实例分析

    C++中链表操作实例分析

    本文给大家分享了个人对于C++中链表操作的理解,并对具体实例进行了分析,是篇非常不错的学习链表操作的文章,希望大家能够喜欢...

    Angel_Kitty8802021-05-23
  • C/C++C/C++详解如何实现文件备份

    C/C++详解如何实现文件备份

    这篇文章主要介绍了C/C++详解如何实现文件备份,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面...

    非池不吃鱼11282022-12-21
  • C/C++基于C++泛型编程职工管理系统

    基于C++泛型编程职工管理系统

    这篇文章主要介绍了基于C++泛型编程职工管理系统,前面介绍到了C++的泛型编程,并实现了万能容器,不过那使用的是数组,今天呢咱带大家实践一下使用泛型...

    酷尔。7092022-09-29
  • C/C++C++实现设计模式之装饰者模式详解

    C++实现设计模式之装饰者模式详解

    这篇文章主要介绍了C++设计模式之装饰模式,装饰模式能够实现动态的为对象添加功能,是从一个对象外部来给对象添加功能,需要的朋友可以参考下...

    今天也要努力搬砖5922022-01-17