如何开发高效服务(C++ )

目录

1. 并发和并行编程模型

1.1 Reactor 模式

1.2 Proactor 模式

2. 设计模式

2.1 单例模式(Singleton)

2.2 工厂模式(Factory)

2.3 观察者模式(Observer)

2.4 策略模式(Strategy)

3. 多线程编程模型

3.1 线程池(Thread Pool)

3.2 任务队列(Task Queue)

4. 网络通信模式

4.1 多路复用(Multiplexing)

总结

实现一个简单的服务器

项目结构

代码实现

1. 线程池类 (ThreadPool)

2. 客户端处理类 (ClientHandler)

3. 服务器类 (Server)

4. 主程序入口 (main.cpp)

说明


在 C++ 开发高效服务器时,常用的开发模式和设计模式能够帮助你构建高效、可扩展和可维护的服务器。以下是一些常见的模式和设计模式:

1. 并发和并行编程模型

1.1 Reactor 模式

Reactor 模式是一种事件驱动设计模式,广泛用于高性能服务器编程。它使用事件分离机制和事件处理器来管理多路 I/O 事件。典型实现包括使用 selectpollepoll 等系统调用。

核心组件:

  • Event Demultiplexer:如 selectepoll,用于等待事件。
  • Event Handler:处理特定事件的回调函数。
  • Synchronous Event De-multiplexer:同步事件分离器,负责监听 I/O 事件。
1.2 Proactor 模式

Proactor 模式是另一种事件驱动设计模式,区别于 Reactor 模式的是它使用异步 I/O 操作。I/O 操作在后台完成,完成后通知应用程序。

核心组件:

  • Asynchronous Operation Processor:执行异步 I/O 操作。
  • Completion Handler:异步操作完成后的回调函数。

2. 设计模式

2.1 单例模式(Singleton)

单例模式确保一个类只有一个实例,并提供一个全局访问点。服务器中的配置管理器或日志管理器通常使用单例模式。

class Singleton {
public:
    static Singleton& getInstance() {
        static Singleton instance;
        return instance;
    }

private:
    Singleton() {}
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
};
2.2 工厂模式(Factory)

工厂模式用于创建对象,而不必指定具体类。它使得代码更加灵活和可扩展。服务器中常用于创建各种处理器或服务。

class AbstractProduct {
public:
    virtual void doSomething() = 0;
    virtual ~AbstractProduct() {}
};

class ConcreteProductA : public AbstractProduct {
public:
    void doSomething() override {
        // Implementation for ConcreteProductA
    }
};

class ConcreteProductB : public AbstractProduct {
public:
    void doSomething() override {
        // Implementation for ConcreteProductB
    }
};

class Factory {
public:
    static std::unique_ptr<AbstractProduct> createProduct(char type) {
        if (type == 'A') return std::make_unique<ConcreteProductA>();
        if (type == 'B') return std::make_unique<ConcreteProductB>();
        return nullptr;
    }
};
2.3 观察者模式(Observer)

观察者模式定义对象间的一对多依赖关系,当一个对象改变状态时,所有依赖它的对象都会收到通知并自动更新。常用于事件系统和通知机制。

class Observer {
public:
    virtual void update() = 0;
};

class Subject {
    std::vector<std::shared_ptr<Observer>> observers;

public:
    void attach(const std::shared_ptr<Observer>& observer) {
        observers.push_back(observer);
    }

    void notify() {
        for (const auto& observer : observers) {
            observer->update();
        }
    }
};
2.4 策略模式(Strategy)

策略模式定义了一系列算法,并将每个算法封装起来,使它们可以互换。服务器中常用于动态选择处理算法或策略。

class Strategy {
public:
    virtual void execute() = 0;
};

class ConcreteStrategyA : public Strategy {
public:
    void execute() override {
        // Implementation of strategy A
    }
};

class ConcreteStrategyB : public Strategy {
public:
    void execute() override {
        // Implementation of strategy B
    }
};

class Context {
    std::unique_ptr<Strategy> strategy;

public:
    void setStrategy(std::unique_ptr<Strategy> newStrategy) {
        strategy = std::move(newStrategy);
    }

    void executeStrategy() {
        if (strategy) {
            strategy->execute();
        }
    }
};

3. 多线程编程模型

3.1 线程池(Thread Pool)

线程池模式预先创建一组线程来处理任务,从而避免了频繁创建和销毁线程的开销。它可以提高服务器的性能和响应速度。

class ThreadPool {
    std::vector<std::thread> workers;
    std::queue<std::function<void()>> tasks;
    std::mutex queueMutex;
    std::condition_variable condition;
    bool stop;

public:
    ThreadPool(size_t threads) : stop(false) {
        for (size_t i = 0; i < threads; ++i) {
            workers.emplace_back([this] {
                while (true) {
                    std::function<void()> task;
                    {
                        std::unique_lock<std::mutex> lock(this->queueMutex);
                        this->condition.wait(lock, [this] {
                            return this->stop || !this->tasks.empty();
                        });
                        if (this->stop && this->tasks.empty()) return;
                        task = std::move(this->tasks.front());
                        this->tasks.pop();
                    }
                    task();
                }
            });
        }
    }

    template<class F>
    void enqueue(F&& f) {
        {
            std::unique_lock<std::mutex> lock(queueMutex);
            tasks.emplace(std::forward<F>(f));
        }
        condition.notify_one();
    }

    ~ThreadPool() {
        {
            std::unique_lock<std::mutex> lock(queueMutex);
            stop = true;
        }
        condition.notify_all();
        for (std::thread &worker : workers) {
            worker.join();
        }
    }
};
3.2 任务队列(Task Queue)

任务队列是一种将任务排队等待处理的机制。可以与线程池结合使用,实现任务的并行处理。

class TaskQueue {
    std::queue<std::function<void()>> tasks;
    std::mutex queueMutex;

public:
    void pushTask(std::function<void()> task) {
        std::lock_guard<std::mutex> lock(queueMutex);
        tasks.push(std::move(task));
    }

    std::function<void()> popTask() {
        std::lock_guard<std::mutex> lock(queueMutex);
        if (tasks.empty()) return nullptr;
        auto task = tasks.front();
        tasks.pop();
        return task;
    }
};

4. 网络通信模式

4.1 多路复用(Multiplexing)

使用 selectpollepoll 实现多路复用,允许单个线程处理多个网络连接。

#include <sys/epoll.h>

int epoll_fd = epoll_create1(0);
struct epoll_event event;
event.events = EPOLLIN;
event.data.fd = listen_fd;
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listen_fd, &event);

while (true) {
    struct epoll_event events[MAX_EVENTS];
    int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
    for (int n = 0; n < nfds; ++n) {
        if (events[n].data.fd == listen_fd) {
            int conn_fd = accept(listen_fd, (struct sockaddr *) &client_addr, &client_len);
            event.data.fd = conn_fd;
            epoll_ctl(epoll_fd, EPOLL_CTL_ADD, conn_fd, &event);
        } else {
            // Handle I/O for events[n].data.fd
        }
    }
}

总结

使用上述开发模式和设计模式,可以构建高效的 C++ 服务器。选择适合的模式和设计模式可以提高代码的可维护性、可扩展性和性能。在实际开发中,可以根据需求组合使用这些模式,构建出高效可靠的服务器应用。

实现一个简单的服务器

以下是一个基于上述开发模式和设计模式的高效 C++ 服务器的示例。该服务器使用了 Reactor 模式、线程池 和其他一些设计模式。

项目结构

我们将项目组织成以下几个部分:

  1. 主程序入口 (main.cpp)
  2. 服务器类 (Server)
  3. 客户端处理类 (ClientHandler)
  4. 线程池类 (ThreadPool)

代码实现

1. 线程池类 (ThreadPool)

我们将先定义一个简单的线程池,用于处理客户端请求。

// ThreadPool.h
#ifndef THREADPOOL_H
#define THREADPOOL_H

#include <vector>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>

class ThreadPool {
public:
    ThreadPool(size_t numThreads);
    ~ThreadPool();

    void enqueue(std::function<void()> task);

private:
    std::vector<std::thread> workers;
    std::queue<std::function<void()>> tasks;
    std::mutex queueMutex;
    std::condition_variable condition;
    bool stop;

    void workerThread();
};

#endif // THREADPOOL_H

// ThreadPool.cpp
#include "ThreadPool.h"

ThreadPool::ThreadPool(size_t numThreads) : stop(false) {
    for (size_t i = 0; i < numThreads; ++i) {
        workers.emplace_back(&ThreadPool::workerThread, this);
    }
}

ThreadPool::~ThreadPool() {
    {
        std::unique_lock<std::mutex> lock(queueMutex);
        stop = true;
    }
    condition.notify_all();
    for (std::thread &worker : workers) {
        worker.join();
    }
}

void ThreadPool::enqueue(std::function<void()> task) {
    {
        std::unique_lock<std::mutex> lock(queueMutex);
        tasks.emplace(std::move(task));
    }
    condition.notify_one();
}

void ThreadPool::workerThread() {
    while (true) {
        std::function<void()> task;
        {
            std::unique_lock<std::mutex> lock(queueMutex);
            condition.wait(lock, [this] { return stop || !tasks.empty(); });
            if (stop && tasks.empty()) {
                return;
            }
            task = std::move(tasks.front());
            tasks.pop();
        }
        task();
    }
}
2. 客户端处理类 (ClientHandler)

处理客户端的连接和请求。

// ClientHandler.h
#ifndef CLIENTHANDLER_H
#define CLIENTHANDLER_H

#include <unistd.h>
#include <iostream>

class ClientHandler {
public:
    ClientHandler(int clientSocket);
    void handle();

private:
    int clientSocket;
};

#endif // CLIENTHANDLER_H

// ClientHandler.cpp
#include "ClientHandler.h"

ClientHandler::ClientHandler(int clientSocket) : clientSocket(clientSocket) {}

void ClientHandler::handle() {
    char buffer[1024];
    ssize_t bytesRead;
    while ((bytesRead = read(clientSocket, buffer, sizeof(buffer))) > 0) {
        std::cout << "Received: " << std::string(buffer, bytesRead) << std::endl;
        write(clientSocket, buffer, bytesRead); // Echo back to client
    }
    close(clientSocket);
}
3. 服务器类 (Server)

服务器类使用 epoll 进行多路复用,并利用线程池处理客户端请求。

// Server.h
#ifndef SERVER_H
#define SERVER_H

#include <netinet/in.h>
#include <sys/epoll.h>
#include <vector>
#include "ThreadPool.h"
#include "ClientHandler.h"

class Server {
public:
    Server(int port, size_t numThreads);
    ~Server();
    void run();

private:
    int serverSocket;
    int epollFd;
    ThreadPool threadPool;

    void acceptConnection();
    void handleClient(int clientSocket);

    static const int MAX_EVENTS = 10;
};

#endif // SERVER_H

// Server.cpp
#include "Server.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <fcntl.h>
#include <cstring>
#include <iostream>

Server::Server(int port, size_t numThreads) : threadPool(numThreads) {
    serverSocket = socket(AF_INET, SOCK_STREAM, 0);
    if (serverSocket == -1) {
        throw std::runtime_error("Failed to create socket");
    }

    int opt = 1;
    setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    sockaddr_in serverAddr;
    std::memset(&serverAddr, 0, sizeof(serverAddr));
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = INADDR_ANY;
    serverAddr.sin_port = htons(port);

    if (bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == -1) {
        throw std::runtime_error("Failed to bind socket");
    }

    if (listen(serverSocket, SOMAXCONN) == -1) {
        throw std::runtime_error("Failed to listen on socket");
    }

    epollFd = epoll_create1(0);
    if (epollFd == -1) {
        throw std::runtime_error("Failed to create epoll file descriptor");
    }

    epoll_event event;
    event.events = EPOLLIN;
    event.data.fd = serverSocket;

    if (epoll_ctl(epollFd, EPOLL_CTL_ADD, serverSocket, &event) == -1) {
        throw std::runtime_error("Failed to add server socket to epoll");
    }
}

Server::~Server() {
    close(serverSocket);
    close(epollFd);
}

void Server::run() {
    epoll_event events[MAX_EVENTS];

    while (true) {
        int numEvents = epoll_wait(epollFd, events, MAX_EVENTS, -1);
        if (numEvents == -1) {
            throw std::runtime_error("Error during epoll wait");
        }

        for (int i = 0; i < numEvents; ++i) {
            if (events[i].data.fd == serverSocket) {
                acceptConnection();
            } else {
                handleClient(events[i].data.fd);
            }
        }
    }
}

void Server::acceptConnection() {
    int clientSocket = accept(serverSocket, nullptr, nullptr);
    if (clientSocket == -1) {
        std::cerr << "Failed to accept client connection" << std::endl;
        return;
    }

    epoll_event event;
    event.events = EPOLLIN | EPOLLET;
    event.data.fd = clientSocket;

    if (epoll_ctl(epollFd, EPOLL_CTL_ADD, clientSocket, &event) == -1) {
        std::cerr << "Failed to add client socket to epoll" << std::endl;
        close(clientSocket);
    }
}

void Server::handleClient(int clientSocket) {
    threadPool.enqueue([clientSocket]() {
        ClientHandler handler(clientSocket);
        handler.handle();
    });
}
4. 主程序入口 (main.cpp)

启动服务器。

// main.cpp
#include "Server.h"

int main() {
    try {
        Server server(8080, 4); // 端口 8080,4 个线程
        server.run();
    } catch (const std::exception &e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return 1;
    }

    return 0;
}

说明

  1. 线程池:我们定义了一个 ThreadPool 类,预先创建线程来处理任务,避免频繁创建和销毁线程的开销。
  2. 客户端处理ClientHandler 类用于处理客户端连接,读取客户端数据并将数据回传。
  3. 服务器Server 类使用 epoll 实现多路复用,监听新连接并将客户端请求交给线程池处理。

通过以上代码,我们创建了一个高效的 C++ 服务器,它利用 epoll 进行多路复用,并使用线程池来处理客户端请求,确保服务器的高性能和高并发处理能力。

  • 18
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

telllong

你的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值