广东平台网站建设找哪家/广州seo站内优化
1 Epoll编程要点
1.1 连接建立
服务器接收客户端连接:
- 接收过程分为两个步骤首先是服务器注册监听listenfd;
- 第二步是服务接收客户端连接clientfd;
- 所有的socket都是利用epoll_ctl交由epoll进行管理
epfd = epoll_create(10);
// 1. 注册监听 listenfd 的读事件
struct epoll_event ev = {0, {0}};
ev.events |= EPOLLIN;
epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev);
// 2. 当触发 listenfd 的读事件,调用 accept 接收新的连接
int clientfd = accept(listenfd, (struct sockaddr*)&client_addr, &len));
struct epoll_event ev = {0, {0}};
ev.events |= EPOLLIN;
epoll_ctl(epfd, EPOLL_CTL_ADD, clientfd, &ev);
客户端连接服务器:
- 客户端连接服务器成功需要客户端发送ack成功才能成功,即写事件EPOLLOUT被触发。
epfd = epoll_create(10);
//创建客户端socket并连接服务器
int connectfd = socket(AF_INET, SOCK_STREAM, 0);
connect(connectfd, (struct sockaddr *)&addr, sizeof(addr));
// 2. 注册监听 connectfd 的写事件
struct epoll_event ev = {0, {0}};
ev.events |= EPOLLOUT;
epoll_ctl(epfd, EPOLL_CTL_ADD, connectfd, &ev);
// 3. 当 connectfd 写事件被触发,连接建立成功
if (status == CONNECTING&& e->events & EPOLLOUT) {status == CONNECTED;
}
1.2 连接断开
- 只有两种模式一种是EPOLLRDHUP读端关闭;
- 另一种是EPOLLHUP读写端都关闭
if (e->events & EPOLLRDHUP) {// 读端关闭read_close(fd);//可以进行写相关操作,之后close(fd);
}
if (e->events & EPOLLHUP) {// 读写端都关闭close(fd);
}
被动断开:
- 对于需要进行半连接操作的,可以利用读端或者写端关闭;操作对于的写端和读端
- read返回值为0 为读端被动关闭;
- write返回值为-1 同时errno数值为EPIPE为写端被动关闭;
//接收端读端被动关闭;发送端写端关闭。
int n = read(fd, buf, size);
if (n == 0) {read_close(fd);//可以进行写相关操作,之后close(fd);
}
//被动写端关闭
int n = write(fd, buf, size);
if (n == -1 && errno == EPIPE) {write_close(fd);//可以进行读相关操作,之后close(fd);
}
1.3 数据到达
- 消息到达需要忽略EINTR系统中断错误;
- 消息到达需要忽略EWOULDBLOCK接收缓冲区为空的错误,当没有数据需要退出循环读数据;
- 其他错误需要:调用close关闭连接
- 数据到达对于水平触发和边沿触发存在差异需要分别考虑
while(1)
{int n = read(fd, buf, size);if (n < 0) { // n == -1if (errno == EINTR)continue;if(errno == EWOULDBLOCK)break;close(fd);} else if (n == 0) {close(fd);} else {// 处理接收数据}
}
1.4 数据发送完毕
- EINTR系统中断直接返回;等待下一次触发写;
- EWOULDBLOCK写缓冲区满返回;写失败需要再次添加写事件等待下一次可写触发。
- wirte写完数据后需要将写事件删除。防止一直触发可写事件。
- 数据发送对于水平触发和边沿触发存在差异需要分别考虑
while(1)
{int n = write(fd, buf, size);if (n == -1) {if (errno == EINTR {continue;}epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);if (errno == EWOULDBLOCK) {struct epoll_event ev = {0, {0}};ev.events = EPOLLOUT;epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);break;}close(fd);}else if (n > 0) {epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);}
}
1.5 epoll事件处理
- epoll_wait设置的MAX_EPOLL_LENGTH大小是就绪队列的大小,决定的是单次可以接收的最大就绪事件,对于整体性能影响不大;
- 最后超时事件可以根据业务设置
while (1) {int nready = epoll_wait(re->epfd, events, MAX_EPOLL_LENGTH, 1000);if (nready < 0) {printf("epoll_wait error, exit\n");continue;}//事件处理
}