探讨read的返回值的三种情况
http://blog.chinaunix.net/uid-23629988-id-3035613.html
- static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
- struct msghdr *msg, size_t size,
- int flags)
- {
- struct sock_iocb *siocb = kiocb_to_siocb(iocb);
- struct scm_cookie tmp_scm;
- struct sock *sk = sock->sk;
- struct unix_sock *u = unix_sk(sk);
- struct sockaddr_un *sunaddr = msg->msg_name;
- int copied = 0;
- int check_creds = 0;
- int target;
- int err = 0;
- long timeo;
- err = -EINVAL;
- if (sk->sk_state != TCP_ESTABLISHED)
- goto out;
- err = -EOPNOTSUPP;
- if (flags&MSG_OOB)
- goto out;
- target = sock_rcvlowat(sk, flags&MSG_WAITALL, size);
- timeo = sock_rcvtimeo(sk, flags&MSG_DONTWAIT);
- msg->msg_namelen = 0;
- /* Lock the socket to prevent queue disordering
- * while sleeps in memcpy_tomsg
- */
- if (!siocb->scm) {
- siocb->scm = &tmp_scm;
- memset(&tmp_scm, 0, sizeof(tmp_scm));
- }
- mutex_lock(&u->readlock);
- do {
- int chunk;
- struct sk_buff *skb;
- unix_state_lock(sk);
- skb = skb_dequeue(&sk->sk_receive_queue);
- if (skb == NULL) {
- if (copied >= target)
- goto unlock;
- /*
- * POSIX 1003.1g mandates this order.
- */
- err = sock_error(sk);
- if (err)
- goto unlock;
- if (sk->sk_shutdown & RCV_SHUTDOWN)
- goto unlock;
- unix_state_unlock(sk);
- err = -EAGAIN;
- if (!timeo)
- break;
- mutex_unlock(&u->readlock);
- timeo = unix_stream_data_wait(sk, timeo);
- if (signal_pending(current)) {
- err = sock_intr_errno(timeo);
- goto out;
- }
- mutex_lock(&u->readlock);
- continue;
- unlock:
- unix_state_unlock(sk);
- break;
- }
- unix_state_unlock(sk);
- if (check_creds) {
- /* Never glue messages from different writers */
- if ((UNIXCB(skb).pid != siocb->scm->pid) ||
- (UNIXCB(skb).cred != siocb->scm->cred)) {
- skb_queue_head(&sk->sk_receive_queue, skb);
- break;
- }
- } else {
- /* Copy credentials */
- scm_set_cred(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).cred);
- check_creds = 1;
- }
- /* Copy address just once */
- if (sunaddr) {
- unix_copy_addr(msg, skb->sk);
- sunaddr = NULL;
- }
- chunk = min_t(unsigned int, skb->len, size);
- if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) {
- skb_queue_head(&sk->sk_receive_queue, skb);
- if (copied == 0)
- copied = -EFAULT;
- break;
- }
- copied += chunk;
- size -= chunk;
- /* Mark read part of skb as used */
- if (!(flags & MSG_PEEK)) {
- skb_pull(skb, chunk);
- if (UNIXCB(skb).fp)
- unix_detach_fds(siocb->scm, skb);
- /* put the skb back if we didn't use it up.. */
- if (skb->len) {
- skb_queue_head(&sk->sk_receive_queue, skb);
- break;
- }
- consume_skb(skb);
- if (siocb->scm->fp)
- break;
- } else {
- /* It is questionable, see note in unix_dgram_recvmsg.
- */
- if (UNIXCB(skb).fp)
- siocb->scm->fp = scm_fp_dup(UNIXCB(skb).fp);
- /* put message back and return */
- skb_queue_head(&sk->sk_receive_queue, skb);
- break;
- }
- } while (size);
- mutex_unlock(&u->readlock);
- scm_recv(sock, msg, siocb->scm, flags);
- out:
- return copied ? : err;
- }
- return copied ? : err;
- err = sock_error(sk);
- if (err)
- goto unlock;
- if (sk->sk_shutdown & RCV_SHUTDOWN)
- goto unlock;
几行代码告诉了我们答案。首先这几行代码是在socket的receive
queue没有数据时,才会运行到达的。当socket没有错误时,会继续坚持socket的RCV_SHUTDOWN标志位,如果设置了该标志位,则
goto 到unlock,直至最后的return返回语句。此时,copied为0时,err也会为0.
sk->sk_shutdown的标志位会在两种情况下被设置,参见unix_shutdown函数。在unix_shutdown函数,由API
close或者shutdown触发,它不仅设置了本端的sk_shutdown标志位,还会设置对端相对应的sk_shutdown标志位。所以无论是
本端还是对端调用shutdown或者close时,都有可能导致本端的read返回为0。这里之所以说可能导致,是因为shutdown时可以指定
shutdown的行为,是关闭发送还是接收。
- timeo = unix_stream_data_wait(sk, timeo);
- if (signal_pending(current)) {
- err = sock_intr_errno(timeo);
- goto out;
- }
几行代码是这个问题的答案。这几行代码同样是处于receive queue为空的判断中。那么,这说明如果receive
queue中已有数据,且大于要读取的字节数,那么在这个函数中,根本就不会去判断是否有pending的信号,返回值为读取的字节数。如果
receive
queue中没有足够的数据,那么就会运行到此处,检查是否有pending的信号。当有信号pending时,这时的返回值就决定于copied的值。
如果已读取了一些字节,那么就返回copied即已读取了的字节数——小于我们要去读取的字节数。如果没有读取任何字节,那么就返回-1,且errno为
EINTR。
前面两个问题以及第一个问题的答案。这个问题的答案也很明显了。在unix_stream_recvmsg中,只要receive
queue中有数据,那么就不会去检查是否sk_shutdown的标志。所以答案是,即使对端关闭socket,本端仍可以读取对端在关闭之前发送的数
据。
探讨read的返回值的三种情况的更多相关文章
- net异步线程获取返回值的三种方式
方式一:endInvoke using System; using System.Collections.Generic; using System.Text; using System.Thread ...
- 自己遇到的ajax调用ashx文件无法获取返回值的一种情况
无法获取返回值的ashx文件大致如下: public void ProcessRequest (HttpContext context) { context.Response.ContentType ...
- 服务器文档下载zip格式 SQL Server SQL分页查询 C#过滤html标签 EF 延时加载与死锁 在JS方法中返回多个值的三种方法(转载) IEnumerable,ICollection,IList接口问题 不吹不擂,你想要的Python面试都在这里了【315+道题】 基于mvc三层架构和ajax技术实现最简单的文件上传 事件管理
服务器文档下载zip格式 刚好这次项目中遇到了这个东西,就来弄一下,挺简单的,但是前台调用的时候弄错了,浪费了大半天的时间,本人也是菜鸟一枚.开始吧.(MVC的) @using Rattan.Co ...
- python执行系统命令后获取返回值的几种方式集合
python执行系统命令后获取返回值的几种方式集合 今天小编就为大家分享一篇python执行系统命令后获取返回值的几种方式集合,具有很好的参考价值,希望对大家有所帮助.一起跟随小编过来看看吧 第一种情 ...
- Activity的跳转及返回值 的四种方法
Activity生命周期 从创建到销毁的生命周期: onCreate()→onStart()→onResume()→onPouse()→onStop()→onDestroy() 从起动到后台再到前台: ...
- Tomcat内存溢出的三种情况及解决办法分析
Tomcat内存溢出的原因 在生产环境中tomcat内存设置不好很容易出现内存溢出.造成内存溢出是不一样的,当然处理方式也不一样. 这里根据平时遇到的情况和相关资料进行一个总结.常见的一般会有下面三种 ...
- SSO单点登录三种情况的实现方式详解
单点登录(SSO——Single Sign On)对于我们来说已经不陌生了.对于大型系统来说使用单点登录可以减少用户很多的麻烦.就拿百度来说吧,百度下面有很多的子系统——百度经验.百度知道.百度文库等 ...
- Spring如何使用JdbcTemplate调用存储过程的三种情况
注:原文 <Spring如何使用JdbcTemplate调用存储过程的三种情况 > Spring的SimpleJdbcTemplate将存储过程的调用进行了良好的封装,下面列出使用Jdbc ...
- SSO单点登录三种情况的实现方式详解(转载)
单点登录(SSO——Single Sign On)对于我们来说已经不陌生了.对于大型系统来说使用单点登录可以减少用户很多的麻烦.就拿百度来说吧,百度下面有很多的子系统——百度经验.百度知道.百度文库等 ...
随机推荐
- 方法:怎么用ionic命令行调试你的ionic app
官网上有很详细的解说 http://blog.ionic.io/live-reload-all-things-ionic-cli/ 下面说说我自己的调试过程(android版): 首先用命令行进入你 ...
- 对于观察者模式,Reactor模式,Proactor模式的一点理解
最近就服务器程序IO效率这一块了解一下设计模式中的Reacotr模式和proactor模式,感觉跟观察者模式有些类似的地方,网上也看了一些其他人对三者之间区别的理解,都讲得很仔细,在此根据自己的理解做 ...
- 在MAC OS X下安装usb转串口驱动(PL2303主控芯片)
本文原创于http://www.cnblogs.com/humaoxiao,非法转载者请自重! 因为最近手里有一块STM32Discovery开发板,所以想搞一下STM32的开发,我前面的 ...
- solaris bind 符号未定义
ld: fatal: Symbol referencing errors Recently, I am learning the Unix C and come to know that Socket ...
- Web性能压力测试工具之Siege详解
PS:Siege是一款开源的压力测试工具,设计用于评估WEB应用在压力下的承受能力.可以根据配置对一个WEB站点进行多用户的并发访问,记录每个用户所有请求过程的相应时间,并在一定数量的并发访问下重复进 ...
- Django Tutorial 学习笔记
实际操作了Django入门教程中的范例,对一些细节有了更清晰的掌握.感觉只看文档不动手是不行的,只看文档没法真正掌握其中要素之间的关系,看了很多遍也不行,必须动手做了才能掌握.同时,这次练习在Ecli ...
- VB 核心编程及通用模块开发 笔记1
前言:学习任何编程语言.编程工具的目的不外乎解决生活问题,能够快速.高效解决问题的方式就是不错的方式,至于选择什么“工具”,众位看官看着办,本人虽然有过3年vb开发经验,但是一直没有深入学习,现已购买 ...
- 正则表达式模块re
正则表达式通过特定的式子匹配某种类型的字符串.对字符串进行匹配验证或者从大量的字符串里提取出特定的信息. 正则表达式包含普通字符和特殊字符.大部分的普通字符如‘A’或‘0’可以简单的来匹配自己.如te ...
- 不得不知道的Python字符串编码相关的知识
开发经常会遇到各种字符串编码的问题,例如报错SyntaxError: Non-ASCII character 'ascii' codec can't encode characters in posi ...
- 关于EndNote X6工具文献管理以及参考文献生成的使用
1 利用endnote下载参考文献 1.1在CNKI中查找文献,在前面打钩,这里显示已经选中两篇文献了。 然后选择导出文献——选择Endnote——导出并保存text文件 打开Endnote——imp ...