事件处理模式
事件处理模式
reactor模式
reactor是一种事件处理模式,出现要解决的问题是要将原本IO管理转变为更关心事件管理,每个事件发生的时候调用回调函数进行处理。
构成
- register 注册事件
- callback 回调函数
- 结构体包括io, event, callback, rbuffer, wbuffer
- 需要注意的是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){
// 这部分就是读取的过程
}
}
}
//
注意
-
读写分离
-
IO与事件分离
-
百万并发连接可能会发生TCP五元组不够的情况1024-65536,这种情况是因为服务器IP端口不够,所以修改服务器IP端口修改即可
-
系统版本不一致也会影响,这是因为/etc/sysctl.conf下的设置问题,老版本file-max也应该修改
-
为什么百万连接之后,客户端,突然关闭服务器也会关闭,这是因为突然有大量连接关闭,CPU需要处理资源处理,解决方法是使用SignalHandler。而且可能因为内存占用多,而终结客户端。