Socket库在C++中的网络事件循环

发布时间:2024-10-29 09:56:28 作者:小樊
来源:亿速云 阅读:79

在C++中,使用Socket库进行网络编程时,通常需要一个事件循环来处理客户端和服务器之间的通信

以下是一个简单的基于Socket库的事件循环示例:

#include <iostream>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <vector>
#include <thread>
#include <mutex>
#include <condition_variable>

class EventLoop {
public:
    EventLoop() : stop_(false) {
        worker_ = std::thread(&EventLoop::run, this);
    }

    ~EventLoop() {
        {
            std::unique_lock<std::mutex> lock(mutex_);
            stop_ = true;
        }
        cond_.notify_one();
        if (worker_.joinable()) {
            worker_.join();
        }
    }

    void add_socket(int sockfd) {
        std::unique_lock<std::mutex> lock(mutex_);
        sockets_.push_back(sockfd);
    }

    void remove_socket(int sockfd) {
        std::unique_lock<std::mutex> lock(mutex_);
        sockets_.erase(std::remove(sockets_.begin(), sockets_.end(), sockfd), sockets_.end());
    }

    void run() {
        while (true) {
            std::vector<int> read_sockets;
            std::vector<int> write_sockets;

            {
                std::unique_lock<std::mutex> lock(mutex_);
                cond_.wait(lock, [this] { return !sockets_.empty() || stop_; });

                for (int sockfd : sockets_) {
                    int events = 0;
                    if (FD_ISSET(sockfd, &read_fds_)) {
                        events |= POLLIN;
                    }
                    if (FD_ISSET(sockfd, &write_fds_)) {
                        events |= POLLOUT;
                    }
                    if (events) {
                        read_sockets.push_back(sockfd);
                    }
                }
            }

            for (int sockfd : read_sockets) {
                handle_read(sockfd);
            }

            for (int sockfd : write_sockets) {
                handle_write(sockfd);
            }
        }
    }

private:
    void handle_read(int sockfd) {
        char buffer[1024];
        ssize_t n = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
        if (n > 0) {
            buffer[n] = '\0';
            std::cout << "Received from " << sockfd << ": " << buffer << std::endl;
        } else if (n == 0) {
            remove_socket(sockfd);
            close(sockfd);
        } else {
            perror("recv");
            remove_socket(sockfd);
            close(sockfd);
        }
    }

    void handle_write(int sockfd) {
        const char* message = "Hello, World!";
        ssize_t n = send(sockfd, message, strlen(message), 0);
        if (n > 0) {
            remove_socket(sockfd);
            close(sockfd);
        } else {
            perror("send");
            remove_socket(sockfd);
            close(sockfd);
        }
    }

    std::thread worker_;
    std::vector<int> sockets_;
    std::mutex mutex_;
    std::condition_variable cond_;
    bool stop_;
    fd_set read_fds_;
    fd_set write_fds_;
};

int main() {
    EventLoop loop;

    int server_sock = socket(AF_INET, SOCK_STREAM, 0);
    if (server_sock == -1) {
        perror("socket");
        return 1;
    }

    struct sockaddr_in server_addr = {0};
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(8080);

    if (bind(server_sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
        perror("bind");
        return 1;
    }

    if (listen(server_sock, 10) == -1) {
        perror("listen");
        return 1;
    }

    struct sockaddr_in client_addr = {0};
    socklen_t client_addr_size = sizeof(client_addr);

    int client_sock = accept(server_sock, (struct sockaddr*)&client_addr, &client_addr_size);
    if (client_sock == -1) {
        perror("accept");
        return 1;
    }

    loop.add_socket(client_sock);

    loop.run();

    close(client_sock);
    close(server_sock);

    return 0;
}

这个示例中,我们创建了一个名为EventLoop的类,它使用一个线程来运行事件循环。事件循环使用select函数来监视多个套接字,当某个套接字准备好进行读/写操作时,相应的事件处理函数将被调用。在这个示例中,我们只处理了读和写事件,但在实际应用中,你可能需要处理更多类型的事件,例如连接建立、断开连接等。

推荐阅读:
  1. 如何实现类似JAVA线程池的C++线程池
  2. C++和Java命令行绘制心形图案

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

c++

上一篇:Socket库在C++中的SSL握手优化

下一篇:C++ Socket库如何避免TCP粘包

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》