事件处理模式

事件处理模式

reactor模式

reactor是一种事件处理模式,出现要解决的问题是要将原本IO管理转变为更关心事件管理,每个事件发生的时候调用回调函数进行处理。

构成

  1. register 注册事件
  2. callback 回调函数
  3. 结构体包括io, event, callback, rbuffer, wbuffer
  4. 需要注意的是event和call_back对应,IO与参数对应

结构

结构的定义要包括五个参数

typedef int (*cb_func)(int);
typedef cb_func CALL_BACK;
strcut connfd{
    int fd;
    char rbuffer[1024];
    char wbuffer[1024];
    int rlength;
    int wlength;
    CALL_BACK send_back;
    union{
        CALL_BACK accept_back;
        CALL_BACK recv_back;
    }recv_accept;
}
struct connfd connfd_list[MAX_CONNFD] = {0};

实现

int accept_cb(int fd){
    struct sockaddr_in client;
    memset(&client , 0, sizeof(client))
    socklen_t len = sizeof(client);
    int clientfd = accept(fd, (struct sockaddr*)&client, &len);
    connfd_list[clientfd] = clientfd;
    connfd_list[clientfd].recv_accept.recv_back = recv_cb;
    connfd_list[clientfd].send_back = recv_cb;
    set_event(clientfd, EPOLLIN, 1);
    return 0;
}
int recv_cb(int fd){
    connfd_list[fd].rbuffer = {0};
    
    int n =recv(fd, connfd_list[fd].rbuffer, MAX_BUFFER_SIZE, 0);
    if(n == 0){
        epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, NULL);
    }
    connfd_list[fd].rlength = n;
    connfd_list[fd].wlength = connfd_list[fd].rlength;
    memcpy(connfd_list[fd].wbuffer,connfd_list[fd].rbuffer,connfd_list[fd].wlength);
    set_event(fd, EPOLLOUT, 0);
    return 0;
}
int send_cb(int fd){
    send(fd, connfd_list[fd].wbuffer, connfd_list[fd].wlength, 0);
    set_event(fd, EPOLLIN, 0);
    return 0;
}
// 注册事件
int set_event(int fd, int event, int op)
    struct epoll_event ev;
    ev.data.fd = fd;
    ev.events = event;
	if(op){
        epoll_ctl(epollfd, EPOLL_CTL_ADD, fd,&ev);
        return 0;
    }else{
        epoll_ctl(epollfd, EPOLL_CTL_MOD, fd,&ev);
    }
	return 0;
}
int init(port, ip){
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    struct sockaddr_in server_addr;
    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sinport = htons(port);
    server_addr.sin_addr.s_addr = inet_addr(ip);
    int ret = bind(sockfd, (stucrt asockaddr*)server_addr. sizeof(server_addr));
    listen(sockfd, 5); // 最多挂起五个连接
    return sockfd;
}
int main(){
    int epollfd = epoll_create(1);
    int listenfd = init(port, ip);
    connfd_list[listenfd].fd = listenfd;
    connfd_list[listenfd].recv_accept.accept_back = accept_cb;
    // 注册
    set_event(listenfd, EPOLLIN, 1);
    
    while(1){ // mainloop
        int nready =  epoll_wait();
        for(int i = 0; i < nready; ++i){
            // 这部分就是读取的过程
        }
    }
}
// 

注意

  1. 读写分离

  2. IO与事件分离

  3. 百万并发连接可能会发生TCP五元组不够的情况1024-65536,这种情况是因为服务器IP端口不够,所以修改服务器IP端口修改即可

  4. 系统版本不一致也会影响,这是因为/etc/sysctl.conf下的设置问题,老版本file-max也应该修改

  5. 为什么百万连接之后,客户端,突然关闭服务器也会关闭,这是因为突然有大量连接关闭,CPU需要处理资源处理,解决方法是使用SignalHandler。而且可能因为内存占用多,而终结客户端。

posted @ 2024-07-22 23:53  LemHou  阅读(1)  评论(0编辑  收藏  举报