网络编程

网络编程关注的问题

连接的建立

分为两种:服务端处理接收客户端的连接,服务端作为客户端连接第三方服务;

int clientfd = accept(listenfd, addr, sz);
// 举例为非阻塞io,阻塞io成功直接返回0;
int connectfd = socket(AF_INET, SOCK_STREAM, 0);
int ret = connect(connectfd, (struct sockaddr *)&addr, sizeof(addr));
// ret == -1 && errno == EINPROGRESS 正在建立连接
// ret == -1 && errno = EISCONN 连接建立成功

连接的断开

分为两种:主动断开和被动断开;

// 主动关闭
close(fd);
shutdown(fd, SHUT_RDWR);
// 主动关闭本地读端,对端写段关闭
shutdown(fd, SHUT_RD);
// 主动关闭本地写端,对端读段关闭
shutdown(fd, SHUT_WR);
// 被动:读端关闭
// 有的网络编程需要支持半关闭状态
int n = read(fd, buf, sz);
if (n == 0) {
close_read(fd);
// write()
// close(fd);
}
// 被动:写端关闭
int n = write(fd, buf, sz);
if (n == -1 && errno == EPIPE) {
close_write(fd);
// close(fd);
}

消息的达到

从读缓冲区中读取数据;

int n = read(fd, buf, sz);
if (n < 0) { // n == -1
if (errno == EINTR || errno == EWOULDBLOCK)
break;
close(fd);
} else if (n == 0) {
close(fd);
} else {
// 处理 buf
}

消息发送完毕

往写缓冲区中写数据;

int n = write(fd, buf, dz);
if (n == -1) {
if (errno == EINTR || errno == EWOULDBLOCK) {
return;
}
close(fd);
}

网络IO职责

检测 IO

io 函数本身可以检测 io 的状态;但是只能检测一个 fd 对应的状态;io 多路复用可以同时检测多
个io的状态;区别是:io函数可以检测具体状态;io 多路复用只能检测出可读、可写、错误、断开
等笼统的事件;

操作IO

只能用IO函数来进行操作;分为阻塞IO和非阻塞IO;

阻塞 IO 和 非阻塞 IO

  • 阻塞在IO线程;

IO多路复用

  • IO 多路复用只负责检测IO,不负责操作IO;

epoll编程

连接建立

// 一、处理客户端的连接
// 1. 注册监听 listenfd 的读事件
struct epoll_event ev;
ev.events |= EPOLLIN;
epoll_ctl(efd, EPOLL_CTL_ADD, listenfd, &ev);
// 2. 当触发 listenfd 的读事件,调用 accept 接收新的连接
int clientfd = accept(listenfd, addr, sz);
struct epoll_event ev;
ev.events |= EPOLLIN;
epoll_ctl(efd, EPOLL_CTL_ADD, clientfd, &ev);
// 二、处理连接第三方服务
// 1. 创建 socket 建立连接
int connectfd = socket(AF_INET, SOCK_STREAM, 0);
connect(connectfd, (struct sockaddr *)&addr, sizeof(addr));
// 2. 注册监听 connectfd 的写事件
struct epoll_event ev;
ev.events |= EPOLLOUT;
epoll_ctl(efd, EPOLL_CTL_ADD, connectfd, &ev);
// 3. 当 connectfd 写事件被触发,连接建立成功
if (status == e_connecting && e->events & EPOLLOUT) {
	status == e_connected;
	// 这里需要把写事件关闭
	epoll_ctl(epfd, EPOLL_CTL_DEL, connectfd, NULL);
}

连接断开

if (e->events & EPOLLRDHUP) {
	// 读端关闭
	close_read(fd);
	close(fd);
}
if (e->events & EPOLLHUP) {
	// 读写端都关闭
	close(fd);
}

数据到达

// reactor 要用非阻塞io
// select
if (e->events & EPOLLIN) {
	while (1) {
		int n = read(fd, buf, sz);
		if (n < 0) {
			if (errno == EINTR)
				continue;
			if (errno == EWOULDBLOCK)
				break;
			close(fd);
		} else if (n == 0) {
			close_read(fd);
			// close(fd);
	}
		// 业务逻辑了
}

数据发送完毕

int n = write(fd, buf, dz);
if (n == -1) {
	if (errno == EINTR)
		continue;
	if (errno == EWOULDBLOCK) {
		struct epoll_event ev;
		ev.events = EPOLLOUT;
		epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);
	}
	close(fd);
}
// ...
if (e->events & EPOLLOUT) {
	int n = write(fd, buf, sz);
	//...
	if (n > 0) {
		epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);
	}
}

reactor

reactor之前写过了,有兴趣可以去看看。

小结

本篇主要写了网络编程关注的问题,网络IO的职责,IO多路复用以及reactor;reactor之前写过,有兴趣可以看下之前的文章。其实,多reactor的模型是很有用的;无论是多线程还是多进程;感兴趣可以一起学习学习。OK,结束。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值