【openwrt】 libubox组件——ustream


在C/C++中经常会提到 ,可能有很多同学对 这个概念不是特别理解,实际上,流只是不同设备间传输的一系列数据的抽象,简单的说,流就是一串数据。如果是这串数据需要对外输出,那么就称这个流为输出流,反之则称为输入流。

ustream 是 libubox 提供的一个流管理工具,它可以实现自动从流中获取数据或者将数据写入流,还可以主动通知ustream的所有者什么时候可以从流读取数据。如果是将数据写入流,会有一个特别的设计——当流可写时,数据会被直接写入流,当流不可写时,数据会被缓存,并在流再次可写时自动地将缓存的数据继续写入流,直到缓存中所有的数据都被写入。

ustream 源码仓库: libubox.git
本文基于

ustream 核心数据结构

ustream 中核心的数据结构关系图如下:
在这里插入图片描述

struct ustream

ustream结构表示一个流管理对象,而流本质上就是一个fd。

struct ustream {
   
   
	struct ustream_buf_list r, w;//流的读写缓存链表
	struct uloop_timeout state_change;//流状态定时器,notify_state()是通过这个定时器回调函数调用的
	struct ustream *next;
	
	// 通知流的owner 可以从流的读缓冲区中读取数据了
	void (*notify_read)(struct ustream *s, int bytes_new);

    // 通知流的owner 可以将数据写入流了
	void (*notify_write)(struct ustream *s, int bytes);

    // 通知流的owner 当前流的状态有变化,一般是异常状态如写错误
	void (*notify_state)(struct ustream *s);

    // 将数据写入流具体函数
	int (*write)(struct ustream *s, const char *buf, int len, bool more);
	
	// 释放一个流
	void (*free)(struct ustream *s);
	
	// 将流设置为读阻塞状态,禁止数据写入流的读缓冲
	void (*set_read_blocked)(struct ustream *s);

	// 监听流状态
	bool (*poll)(struct ustream *s);

	/*
	 * ustream user should set this if the input stream is expected
	 * to contain string data. the core will keep all data 0-terminated.
	 */
	bool string_data; // 流是否是字符串数据
	bool write_error; // 是否发生写错误
	bool eof, eof_write_done; // 是否到达EOF

	enum read_blocked_reason read_blocked;// 流不可读的原因
};

enum read_blocked_reason {
   
   
	READ_BLOCKED_USER = (1 << 0), // 用户主动禁止从流读取数据
	READ_BLOCKED_FULL = (1 << 1), // 流已经满了,主要指的是读缓冲区满了
};

struct ustream_buf_list

ustream_buf_list 表示一个ustream buf 链表,每个流对应读和写2个链表。此结构在创建ustream时自动创建,不需要用户单独定义。

struct ustream_buf_list {
   
   
	struct ustream_buf *head; // 指向第一个ustream_buf
	struct ustream_buf *data_tail; // 指向第一个尚未使用或者未使用完的ustream_buf
	struct ustream_buf *tail;// 指向最后一个ustream_buf

	int (*alloc)(struct ustream *s, struct ustream_buf_list *l);// 申请新的ustream_buf函数

	int data_bytes;//当前ustream_buf_list里面总的数据量

	int min_buffers;//当前ustream_buf_list 最少的 ustream_buf 个数
	int max_buffers;//当前ustream_buf_list 最多的 ustream_buf 个数
	int buffer_len;//单个 ustream_buf 大小

	int buffers;//当前 ustream_buf_list 实际的 ustream_buf 个数
};

struct ustream_buf

ustream_buf 是实际存放数据的buffer,ustream_buf 通常有多个。

struct ustream_buf {
   
   
	struct ustream_buf *next; // 指向下一个ustream_buf

	char *data;//指向 ustream_buf 还没有被读写的位置
	char *tail;//指向 ustream_buf 尚未使用的位置
	char *end;// 指向 ustream_buf 末尾

	char head[]; // 用于存放实际的数据区
};

ustream_buf_list 和 ustream_buf 之间的关系如下图所示:

在这里插入图片描述

struct ustream_fd

stream 是流管理对象,前面有提到,流本质上就是一个fd,uloop_fd 会关联此fd。

struct ustream_fd {
   
   
	struct ustream stream;
	struct uloop_fd fd;// 保存和当前ustream关联的fd,后续会使用uloop_run监听这个fd
};

ustream 核心API

ustream_fd_init

初始化一个ustream,注意到此函数除了接收 ustream_fd 参数,还需要关联一个fd(也就是流),这个fd 必须是“可poll”的,也就是说它只能是设备文件或者socket文件,以及pipe、fifo这类特殊设备文件,不可以是普通文件。
初始化之后默认就会开始监听fd的可读事件,不会监听可写事件,可写事件会在满足一定条件后才会监听。

void ustream_fd_init(struct ustream_fd *sf, int fd)
{
   
   
	struct ustream *s = &sf->stream;

	ustream_init_defaults(s);// 初始化ustream一些基础参数,比如ustream_buf的最大个数、大小等

	sf->fd.fd = fd;
	sf->fd.cb = ustream_uloop_cb;// fd 可读或者可写事件回调,由uloop_run调用
	s->set_read_blocked = ustream_fd_set_read_blocked;
	s->write = ustream_fd_write;// 将ustream写缓冲区里面的数据写入fd
	s->free = ustream_fd_free;
	s->poll = ustream_fd_poll;
	ustream_fd_set_uloop(s, false);// 由uloop_run监听这个fd
}

ustream_uloop_cb

ustream_uloop_cb 是前面ustream_fd->fd 的可读写事件回调函数,当fd满足可读/写事件后就会自动调用此函数进行处理。

static void ustream_uloop_cb(struct uloop_fd *fd, unsigned int events)
{
   
   
	struct ustream_fd *sf = container_of(fd, struct ustream_fd, fd);

	__ustream_fd_poll(sf, events);
}

static bool __ustream_fd_poll(struct ustream_fd *sf, unsigned int events)
{
   
   
	struct ustream *s = &sf->stream;
	bool more = false;

	if (events & ULOOP_READ)
		ustream_fd_read_pending(sf, &more);// 处理可读事件

	if (events & ULOOP_WRITE) {
   
   
		bool no_more = ustream_write_pending
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

知否,知否

来一杯冰美式把

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值