“
上篇文章
提到阻塞(block)一下如何read数据
这里针对是非阻塞如何read数据
并且纠正前面出现几个错误
(1) 非阻塞 遇到errno=EAGAIN必须continue处理 ,epoll_wait 下次还能触发吗?
(2) 服务器read一次数据 ,只解析一个包的数据
会不会出现每次客户端发送新数据 但是服务器读取仍然是历史发送记录,
缓存里留着未处理数据情况
”
在一个异步非阻塞的socket上调用read/write函数读为2个步骤
步骤1 调用read从系统 层读取到应用层
步骤2 解析数据
—
01
—
步骤1 调用read从系统buffer读取到应用层buffer
epoll提供两种工作模式:LT和ETLevel-Triggered and Edge-Triggered
区别是:
前者触发多次,下次触发条件:
只 要缓冲区有数据,不区分是上次未读取还是新来的
后者只 触发一次 下次触发条件:
1 有新的数据写入管道 缓冲区有数据 (consume the whole buffer data)
2 遇到EAGAIN (return EAGAIN)
3 缓冲区有数据但是属于上次遗留的 不触发
参考 man epoll 例子
如果是ET模式,管道中剩余的1KB被挂起,再次调用epoll_wait,得不到管道读者的文件句柄,除 非有新的数据写入管道
如果是LT模式,只要管道中有数据可读,每次调用epoll_wait都会触发。
//所以,在epoll的ET模式下,正确的读写方式为:
读:只要可读,就一直读,直到返回0,或者 errno = EAGAIN(break 满足下次触发条件)
写:只要可写,就一直写,直到数据发送完,或者 errno = EAGAIN(break 满足下次触发条件)
在epoll的LT模式下相反
读:忽略掉errno = EAGAIN的错误,下次继续读 continue
写:忽略掉errno = EAGAIN的错误,下次继续写
ET
—
02
—
步骤2 解析数据
说明: 这里约定数据包是指是客户端发送一次的数据
应用层 利用socket从系统底层缓冲区(buffer)read一次n字节大小数据到本地buffer
这些数据
可能客户端发送数据过大一个包拆拆分多个包发送,
也可能数据过小
多个包合并成一个包发送,
也可能就是客户端连续发送多次
解析n字节大小数据 步骤
1 小于一个包 俗称半包
判断bytebuffer中剩余数据是否足够一个包,不够继续系统缓冲区读取 IO操作
2 完整的一个包
读取一个包之后,剩余数据为零继续等待客户端下一个请求IO操作
3 包涵:多个包
继续解析,知道满足条件1和2为止
解包
关于同步和异步后面在详细说明
blocking I/O
nonblocking I/O
I/O multiplexing (select and poll)
signal driven I/O (SIGIO)
asynchronous I/O (the POSIX aio_functions)
io
本章节内容:
socket之send与发送缓冲区大小的没有任何关系
主要原因是发送缓冲区大小和接受缓冲大小可以设置任意数值
造成了这 一个数据包被多次接受才算完整
异步非阻塞的socket上调用read/write函数读为2个步骤
步骤1 如何读取数据,注意是遇到错误该如何处理
步骤2:如何处理这些数据,注意黏合包,半包如何处理
下章预告:
大纲
这次提到tcp数据流无边界特点
还有一个特点那就是 TCP协议中有长连接和短连接之分
需要心跳包传统的 keepAlive有什么缺点,为什么非要自己实现
计划:
plan
喜欢
分享
or
领取专属 10元无门槛券
私享最新 技术干货