网络学习-reactor模式(五)

一、reactor是什么?

1、reactor是一种基于事件驱动的模式,它将IO操作和业务逻辑分离,通过注册回调函数来处理不同的IO事件,从而实现非阻塞的IO操作。

2、相比于传统的同步阻塞IO模型,它具有更高的并发性能和更好的资源利用率。

3、由原来的IO管理,变为对事件管理;对不同的IO事件,执行对应不同的回调;更多关注于事件的管理,简化对IO操作的关注。

二、如何实现reactor

1、技术点

1、使用epoll

2、使用回调函数

2、关注点

1、event与callback的匹配

2、每一个IO与之对应参数的传递

/*
    io------------> event -----------> callback
listenfd----------> EPOLLIN-----------> accept_cb
clientfd----------> EPOLLIN-----------> recv_cb
clientfd----------> EPOLLOUT----------> send_cb
*/

三、具体实操

1、将IO管理变为事件管理

/*
     io             ---io管理总的就这么些内容
    event           ---可读,可写,可出错
    callback        ---事件管理的精髓,执行响应的动作
    rbuffer         ---接收数据的缓冲区
    rlength         ---接收数据的长度
    wbuffer         ---发送数据的缓冲区
    wlength         ---发送数据的长度
*/
typedef struct ConnectSt{
    char rbuffer[BUFFER_SIZE];
    char wbuffer[BUFFER_SIZE];

    int fd;
    int rlen;
    int wlen;

    RCALLBACK send_callback;        //对应EPOLLOUT事件
    union {
        RCALLBACK recv_callback;    //对应EPOLLIN事件
        RCALLBACK accept_callback;  //对应EPOLLIN事件
    }recv_or_accept;   
}Conne;

2、回调函数的实现

1、注册回调函数

typedef int (*RCALLBACK)(int fd);
int Accept_cb(int fd);
int Recv_cb(int fd);
int Send_cb(int fd);
int EventRegister(int fd, int event);
int SetEvent(int fd, int event, int flag)

2、回调函数的实现

//listen(socketfd)-------> EPOLLIN------------->Accept_cb
int Accept_cb(int fd)
{
    struct sockaddr_in clientaddr; //创建一个客户端用于接收数据
    socklen_t len = sizeof(clientaddr);

    cout<<"current socketfd:"< EPOLLIN-----------> recv_cb
int Recv_cb(int fd)
{
    int count = recv(fd, conn_poll[fd].rbuffer, BUFFER_SIZE, 0);
    if (count == 0)
    {
        cout << "client close" << endl;
        close(conn_poll[fd].fd);                                // 关闭客户端的连接描述
        epoll_ctl(fd, EPOLL_CTL_DEL, conn_poll[fd].fd, NULL); // 将客户端的连接描述符从epoll实例中删除
        return 0;
    }
    cout << "recv_buffer:" << conn_poll[fd].rbuffer << endl;

    conn_poll[fd].wlen = count;
    memcpy(conn_poll[fd].wbuffer, conn_poll[fd].rbuffer, count);

    SetEvent(fd, EPOLLOUT,0); //监听可写事件

    return count;
}

//clientfd----------> EPOLLOUT----------> send_cb
int Send_cb(int fd)
{
    // 返回信息
    int count = send(fd, conn_poll[fd].wbuffer, conn_poll[fd].wlen, 0);

    SetEvent(fd, EPOLLIN,0); //监听可读事件

    return count;
}

//将事件注册到epoll中的代码进行复用
int EventRegister(int fd, int event)
{
    if(fd < 0 || fd >= CONNECTIONS_SIZE){
        cout<<"fd is invalid"<

3、事件驱动基本框架已经搭建完毕,在epoll_wait中,只需要判断事件类型即可。

struct epoll_event events[1024]={0};
int nready = epoll_wait(epfd, events, 1024, -1); //等待IO就绪
cout<<"nready:"<

网络学习-reactor模式(五)_第1张图片

4、小结

1、将IO管理变为事件管理,使得程序更加灵活,后续需要添加新的IO操作,只需要注册回调函数即可。
2、回调函数的实现,使得程序更加简洁。
3、reactor更多的是提供一种解决网络IO多路复用的思路,并不是一个具体的实现,只是在当下服务器并发数量较大时,采用绑定epoll和回调函数来实现;当并发数量很少时,也可以将epoll替换为select或者poll。

四、总结

1、将IO管理变为事件管理,使得程序更加灵活,后续需要添加新的IO操作,只需要注册回调函数即可。

2、回调函数的实现,使得程序更加简洁。

3、事件驱动基本框架已经搭建完毕,在epoll_wait中,只需要判断事件类型即可。

4、reactor是一种基于事件驱动的模式,它将IO操作和业务逻辑分离,通过注册回调函数来处理不同的IO事件,从而实现非阻塞的IO操作。相比于传统的同步阻塞IO模型,它具有更高的并发性能和更好的资源利用率。

5、与epoll的区别在于,epoll是基于内核实现的,而reactor是基于用户态的实现。

6、reactor更多的是提供一种解决网络IO多路复用的思路,并不是一个具体的实现,只是在当下服务器并发数量较大时,采用绑定epoll和回调函数来实现;当并发数量很少时,也可以将epoll替换为select或者poll。

Code:
https://github.com/LengYa/reactorDemo.git

你可能感兴趣的:(网络编程,网络,学习)