转自:http://blog.csdn.net/atefrice/article/details/47861891
一、zebra 中的 源码,readn、writen
二、调用readn、writen的原因
1、socket上的read write操作不同与一般的文件IO操作;
2、socket上的用read write读写的字节数可能比要求的少,但这并不是错误;
3、原因是socket的缓冲区可能已经到达了极限,或者被信号中断;
4、所以,此时所需要的就是再次调用read write以写入或输出剩余的字符,于是有了 readn、writen。
三、readn的代码分析
原文链接:http://m.blog.csdn.net/blog/u011542994/44684173
1、nleft表示还剩下的字节数;nread表示已经读取的字节数
2、接着是一个字符型指针变量:ptr,指向读取的目标缓冲区(ptr = vptr)
3、我们要读取的时n字节的数据,于是就先将赋值:nleft = n;(当前初始时,还剩了n个字节等待读取呢)
4、接着进入循环while,只要还剩下了字节也就是 nleft>0,就进入循环:
5、开始read, if( nread < 0 ),意味着read函数这里出现了问题(也许是出错了,也许是中断影响了它)
6、接着进行问题的处理:errno 是记录系统的最后一次错误代码(在errno.h中定义);
7、而EINTR则是返回状态,不同函数意义不同;
8、read中表示:由于信号中断,没读到任何数据;
9、if(errno == EINTR)意思就是说如果read是因为中断导致返回负数(nread < 0),那么此时将nread置0;
即:nread = 0,表示什么也没有读取到,那么此时还要继续重新再次调用read函数,再次读取数据(依然在
while循环内进行);
10、如果不是因为中断导致read异常那么就返回-1,跳出循环;
11、如果nread = 0,说明此时数据数据已经读取完了或者对端关闭连接,也是要跳出循环。
12、最后函数返回读取的字节数(极端情况就是nleft = 0了,也就是没有剩余的数据,显然返回的就是n;那么只要 nleft>0,while会一直进行下去)
13、writen 类似。
四、read返回值分析
注意: 源代码级详细精彩的分析在这里 原文链接:http://blog.chinaunix.net/uid-23629988-id-3035613.html
以下只是概括:
1、当receive queue 为空时, socket错误或者 对端 close、shutdown都会导致read 返回0;
2、若receive queue 小于请求 read 字节数时,才会进入 判断是否有 信号pending,
如果有信号,呢么返回值受 copied 值确定,
若copied > 0, 则返回值即为copied(必然小于请求字节),
若copied ==0,则返回值为-1, 并且errno 被设定为EINTR;
若receive queue 大于 请求 read 字节数时,则不会 进行 信号pending 的检查。
3、综上,对端关闭后,是否可以读取对端在关闭之前发送的数据??
答:只要receive queue中有数据,就不会去检查是否sk_shutdown的标志(对端close或shutdown产生该标志);
只要receive queue中有足够的数据,就不会去检查 是否有信号pending;
因此,即使对端关闭socket,本端仍可以读取对端在关闭之前发送的数据!!!!!
五、从tcp报文角度,分析一端挂死
注意: 原文链接:http://blog.163.com/xychenbaihu@yeah/blog/static/132229655201212075929354/
如上图所示,
1、Server进程被终止,此时Server会正常发送FIN包给Client
操作系统在回收socket描述符时,就像close一样,会发送FIN包给Client。
2、如果此时Client继续向Server写数据,那么会触发一个RST包。
3、总结: 在Linux下,无论是read位于FIN包和RST包之间,还是read位于FIN包和RST包之后,read都将返回0。 所以当read返回0时,可以确认对方已经关闭了连接,所以接下来应该关闭socket描述符。
当TCP的发送队列中还有数据没有发送完成时,调用close操作,不会发送FIN包,而是发送RST包。
一、zebra 中的 源码,readn、writen
二、调用readn、writen的原因
1、socket上的read write操作不同与一般的文件IO操作;
2、socket上的用read write读写的字节数可能比要求的少,但这并不是错误;
3、原因是socket的缓冲区可能已经到达了极限,或者被信号中断;
4、所以,此时所需要的就是再次调用read write以写入或输出剩余的字符,于是有了 readn、writen。
三、readn的代码分析
原文链接:http://m.blog.csdn.net/blog/u011542994/44684173
1、nleft表示还剩下的字节数;nread表示已经读取的字节数
2、接着是一个字符型指针变量:ptr,指向读取的目标缓冲区(ptr = vptr)
3、我们要读取的时n字节的数据,于是就先将赋值:nleft = n;(当前初始时,还剩了n个字节等待读取呢)
4、接着进入循环while,只要还剩下了字节也就是 nleft>0,就进入循环:
5、开始read, if( nread < 0 ),意味着read函数这里出现了问题(也许是出错了,也许是中断影响了它)
6、接着进行问题的处理:errno 是记录系统的最后一次错误代码(在errno.h中定义);
7、而EINTR则是返回状态,不同函数意义不同;
8、read中表示:由于信号中断,没读到任何数据;
9、if(errno == EINTR)意思就是说如果read是因为中断导致返回负数(nread < 0),那么此时将nread置0;
即:nread = 0,表示什么也没有读取到,那么此时还要继续重新再次调用read函数,再次读取数据(依然在
while循环内进行);
10、如果不是因为中断导致read异常那么就返回-1,跳出循环;
11、如果nread = 0,说明此时数据数据已经读取完了或者对端关闭连接,也是要跳出循环。
12、最后函数返回读取的字节数(极端情况就是nleft = 0了,也就是没有剩余的数据,显然返回的就是n;那么只要 nleft>0,while会一直进行下去)
13、writen 类似。
四、read返回值分析
注意: 源代码级详细精彩的分析在这里 原文链接:http://blog.chinaunix.net/uid-23629988-id-3035613.html
以下只是概括:
1、当receive queue 为空时, socket错误或者 对端 close、shutdown都会导致read 返回0;
2、若receive queue 小于请求 read 字节数时,才会进入 判断是否有 信号pending,
如果有信号,呢么返回值受 copied 值确定,
若copied > 0, 则返回值即为copied(必然小于请求字节),
若copied ==0,则返回值为-1, 并且errno 被设定为EINTR;
若receive queue 大于 请求 read 字节数时,则不会 进行 信号pending 的检查。
3、综上,对端关闭后,是否可以读取对端在关闭之前发送的数据??
答:只要receive queue中有数据,就不会去检查是否sk_shutdown的标志(对端close或shutdown产生该标志);
只要receive queue中有足够的数据,就不会去检查 是否有信号pending;
因此,即使对端关闭socket,本端仍可以读取对端在关闭之前发送的数据!!!!!
五、从tcp报文角度,分析一端挂死
注意: 原文链接:http://blog.163.com/xychenbaihu@yeah/blog/static/132229655201212075929354/
如上图所示,
1、Server进程被终止,此时Server会正常发送FIN包给Client
操作系统在回收socket描述符时,就像close一样,会发送FIN包给Client。
2、如果此时Client继续向Server写数据,那么会触发一个RST包。
3、总结: 在Linux下,无论是read位于FIN包和RST包之间,还是read位于FIN包和RST包之后,read都将返回0。 所以当read返回0时,可以确认对方已经关闭了连接,所以接下来应该关闭socket描述符。
当TCP的发送队列中还有数据没有发送完成时,调用close操作,不会发送FIN包,而是发送RST包。