ZBLOG

reactor对新来的连接如何处理

在使用 Reactor 模式处理新来的连接时,通常会遵循以下步骤。Reactor 模式主要用于事件驱动的网络编程,它通过分离事件处理和事件循环来实现高效的并发连接管理。

Reactor 模式处理新连接的步骤

  1. 创建监听套接字: 首先,创建一个监听套接字并绑定到指定端口。将该套接字设置为非阻塞模式,以避免在接受新连接时造成阻塞。
   int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
   fcntl(listen_fd, F_SETFL, O_NONBLOCK); // 设置非阻塞模式

   struct sockaddr_in server_addr;
   server_addr.sin_family = AF_INET;
   server_addr.sin_addr.s_addr = INADDR_ANY;
   server_addr.sin_port = htons(port);

   bind(listen_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
   listen(listen_fd, SOMAXCONN); // 开始监听
  1. 创建 I/O 多路复用器: 创建一个 I/O 多路复用器(如 epollselect),用于监控监听套接字和后续的客户端连接。

  2. 注册监听事件: 将监听套接字注册到 I/O 多路复用器中,并指定感兴趣的事件(通常是可读事件)。

  3. 进入事件循环: 进入主事件循环,等待可读事件发生。

  4. 处理新来的连接: 一旦检测到有新的可读事件(即有新的客户端连接请求),执行以下步骤:

    • 使用 accept() 接受新连接。
    • 将新建立的连接设置为非阻塞模式。
    • 注册新连接到 I/O 多路复用器中,以便能监测其后续的数据传输。

示例代码

下面是一个简单的示例,演示了如何在 Reactor 模式下处理新来的 TCP 连接:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define MAX_EVENTS 1024
#define PORT 8080

void set_nonblocking(int sockfd) {
    int flags = fcntl(sockfd, F_GETFL);
    fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
}

int main() {
    int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
    
    set_nonblocking(listen_fd); // 设置为非阻塞
    
    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(PORT);
    
    bind(listen_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
    
    listen(listen_fd, SOMAXCONN); // 开始监听

    // 创建 epoll 实例
    int epfd = epoll_create1(0);
    
    struct epoll_event ev;
    ev.events = EPOLLIN; // 可读事件
    ev.data.fd = listen_fd; 
   
    epoll_ctl(epfd, EPOLL_CTL_ADD, listen_fd, &ev); // 注册监听 fd 到 epoll

    while (1) {
        struct epoll_event events[MAX_EVENTS];
        int nready = epoll_wait(epfd, events, MAX_EVENTS, -1); // 阻塞等待
        
        for (int i = 0; i < nready; ++i) {
            if (events[i].data.fd == listen_fd) { // 检测是否为监听 fd
                while (1) {
                    struct sockaddr_in client_addr;
                    socklen_t addr_len = sizeof(client_addr);
                    
                    int conn_fd = accept(listen_fd, (struct sockaddr*)&client_addr, &addr_len);
                    if (conn_fd < 0) {
                        if (errno == EAGAIN || errno == EWOULDBLOCK)
                            break; // 没有更多可以接受的连接
                        perror("accept");
                        break;
                    }
                    
                    set_nonblocking(conn_fd); // 新链接设为非阻塞
                    
                    // 将新链接注册到 epoll 中以监视可读事件
                    ev.events = EPOLLIN | EPOLLET; // 边缘触发
                    ev.data.fd = conn_fd;

                    epoll_ctl(epfd, EPOLL_CTL_ADD, conn_fd , &ev); 
                }
            } else {
                // 此处可以添加对已建立客户端链接数据读取逻辑的处理...
            }
        }
    }

    close(listen_fd);
}

注意事项

  • 异常处理: 确保在调用系统调用时进行错误检查,如 socket(), bind(), listen(), 和 accept() 等函数。

  • 资源管理: 不要忘记关闭不再使用的文件描述符,以避免资源泄漏。

  • 数据读取与写入: 当新连接被接受后,需要适当设计逻辑来读取和写入数据,同时考虑选择边缘触发(EPOLLET)或水平触发(EPOLLET)的工作方式,根据实际需求做出决定。

Reactor 模式非常适合于高性能网络服务,可以有效地管理大量并发网络连接。


内容由零声教学AI助手提供,问题来源于学员提问

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:http://sdn.0voice.com/?id=7944

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?