企业级TCP处理要点-epoll编程

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 == -1
		if (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;
		}
		//事件处理
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值