摘要:的数据结构数据结构中是链表元素的个数,是缓冲区创建时,链表元素约定的大小实际大小不一定是这个值,是实际上缓冲区占用的内存总大小。中的有三种,分别应用于缓存数据发送文件提醒连接关闭三种情景。指的是元素的内存大小。
前言
swoole 中数据的接受与发送(例如 reactor 线程接受客户端消息、发送给客户端的消息、接受到的来自 worker 的消息、要发送给 worker 的消息等等)都要涉及到缓冲区,swoole 中的缓冲区实现是 swBuffer,实际上是一个单链表。
swBuffer 的数据结构swBuffer 数据结构中 trunk_num 是链表元素的个数,trunk_size 是 swBuffer 缓冲区创建时,链表元素约定的大小(实际大小不一定是这个值),length 是实际上缓冲区占用的内存总大小。
swBuffer_trunk 中的 type 有三种,分别应用于:缓存数据、发送文件、提醒连接关闭三种情景。length 指的是元素的内存大小。
enum swBufferChunk { SW_CHUNK_DATA, SW_CHUNK_SENDFILE, SW_CHUNK_CLOSE, }; typedef struct _swBuffer_trunk { uint32_t type; uint32_t length; uint32_t offset; union { void *ptr; struct { uint32_t val1; uint32_t val2; } data; } store; uint32_t size; void (*destroy)(struct _swBuffer_trunk *chunk); struct _swBuffer_trunk *next; } swBuffer_trunk; typedef struct _swBuffer { int fd; uint8_t trunk_num; //trunk数量 uint16_t trunk_size; uint32_t length; swBuffer_trunk *head; swBuffer_trunk *tail; } swBuffer;swBuffer 的创建
swBuffer 的创建很简单,只是初始化整个 swBuffer 的 header 头元素而已:
swBuffer* swBuffer_new(int trunk_size) { swBuffer *buffer = sw_malloc(sizeof(swBuffer)); if (buffer == NULL) { swWarn("malloc for buffer failed. Error: %s[%d]", strerror(errno), errno); return NULL; } bzero(buffer, sizeof(swBuffer)); buffer->trunk_size = trunk_size; return buffer; }swBuffer 内存的申请
swBuffer 内存的申请逻辑也很简单,按照传入的 size 参数为链表元素申请内存,初始化成员变量,然后将链表元素放到链表的尾部即可:
int swBuffer_append(swBuffer *buffer, void *data, uint32_t size) { swBuffer_trunk *chunk = swBuffer_new_trunk(buffer, SW_CHUNK_DATA, size); if (chunk == NULL) { return SW_ERR; } buffer->length += size; chunk->length = size; memcpy(chunk->store.ptr, data, size); swTraceLog(SW_TRACE_BUFFER, "trunk_n=%d|size=%d|trunk_len=%d|trunk=%p", buffer->trunk_num, size, chunk->length, chunk); return SW_OK; } swBuffer_trunk *swBuffer_new_trunk(swBuffer *buffer, uint32_t type, uint32_t size) { swBuffer_trunk *chunk = sw_malloc(sizeof(swBuffer_trunk)); if (chunk == NULL) { swWarn("malloc for trunk failed. Error: %s[%d]", strerror(errno), errno); return NULL; } bzero(chunk, sizeof(swBuffer_trunk)); //require alloc memory if (type == SW_CHUNK_DATA && size > 0) { void *buf = sw_malloc(size); if (buf == NULL) { swWarn("malloc(%d) for data failed. Error: %s[%d]", size, strerror(errno), errno); sw_free(chunk); return NULL; } chunk->size = size; chunk->store.ptr = buf; } chunk->type = type; buffer->trunk_num ++; if (buffer->head == NULL) { buffer->tail = buffer->head = chunk; } else { buffer->tail->next = chunk; buffer->tail = chunk; } return chunk; }获取 swBuffer 的元素
从 swBuffer 缓冲区拿数据只能从 head 中获取:
#define swBuffer_get_trunk(buffer) (buffer->head)swBuffer 元素的 pop
获取了缓冲区的元素之后,就要相应删除 head 链表元素:
void swBuffer_pop_trunk(swBuffer *buffer, swBuffer_trunk *chunk) { if (chunk->next == NULL) { buffer->head = NULL; buffer->tail = NULL; buffer->length = 0; buffer->trunk_num = 0; } else { buffer->head = chunk->next; buffer->length -= chunk->length; buffer->trunk_num--; } if (chunk->type == SW_CHUNK_DATA) { sw_free(chunk->store.ptr); } if (chunk->destroy) { chunk->destroy(chunk); } sw_free(chunk); }swBuffer 缓冲区的销毁
int swBuffer_free(swBuffer *buffer) { volatile swBuffer_trunk *chunk = buffer->head; void * *will_free_trunk; //free the point while (chunk != NULL) { if (chunk->type == SW_CHUNK_DATA) { sw_free(chunk->store.ptr); } will_free_trunk = (void *) chunk; chunk = chunk->next; sw_free(will_free_trunk); } sw_free(buffer); return SW_OK; }
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/29221.html
前言 作为一个网络框架,最为核心的就是消息的接受与发送。高效的 reactor 模式一直是众多网络框架的首要选择,本节主要讲解 swoole 中的 reactor 模块。 UNP 学习笔记——IO 复用 Reactor 的数据结构 Reactor 的数据结构比较复杂,首先 object 是具体 Reactor 对象的首地址,ptr 是拥有 Reactor 对象的类的指针, event_nu...
摘要:之后如果仍然有剩余未发送的数据,那么就如果已经没有剩余数据了,继续去取下一个数据包。拿到后,要用函数转化为相应的类型即可得到包长值。 swPort_onRead_check_eof EOF 自动分包 我们前面说过,swPort_onRead_raw 是最简单的向 worker 进程发送数据包的方法,swoole 会将从客户端接受到的数据包,立刻发送给 worker 进程,用户自己把...
摘要:线程在建立之时,就会调用函数开启事件循环。如果为空,那么重新设置文件描述符的监听事件,删除写就绪,只设置读就绪。这个是水平触发模式的必要步骤,避免无数据写入时,频繁地调用写就绪回调函数。 前言 经过 php_swoole_server_before_start 调用 swReactorThread_create 创建了 serv->reactor_threads 对象后,swServe...
摘要:当其就绪时,会调用执行定时函数。进程超时停止进程将要停止时,并不会立刻停止,而是会等待事件循环结束后停止,这时为了防止进程不退出,还设置了的延迟,超过就会停止该进程。当允许空闲时间小于时,统一每隔检测空闲连接。 前言 swoole 的 timer 模块功能有三个:用户定时任务、剔除空闲连接、更新 server 时间。timer 模块的底层有两种,一种是基于 alarm 信号,一种是基于...
摘要:前言我们知道,由于没有多线程模型,所以更多的使用多进程模型,因此代码相对来说更加简洁,减少了各种线程锁的阻塞与同步,但是也带来了新的问题数据同步。相比多线程之前可以直接共享进程的内存,进程之间数据的相互同步依赖于共享内存。 前言 我们知道,由于 PHP 没有多线程模型,所以 swoole 更多的使用多进程模型,因此代码相对来说更加简洁,减少了各种线程锁的阻塞与同步,但是也带来了新的问题...
阅读 761·2023-04-25 20:47
阅读 2515·2019-08-30 15:53
阅读 917·2019-08-26 14:05
阅读 863·2019-08-26 11:59
阅读 1660·2019-08-26 11:43
阅读 1577·2019-08-26 10:57
阅读 1332·2019-08-23 18:23
阅读 2585·2019-08-23 12:57