探讨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)对于我们来说已经不陌生了.对于大型系统来说使用单点登录可以减少用户很多的麻烦.就拿百度来说吧,百度下面有很多的子系统——百度经验.百度知道.百度文库等 ...
随机推荐
- [转载]IIS下开启php扩展失效? 感谢作者 本人泪流满面
用户反应,空间不支持GD.系统环境是IIS PHP. 先用phpinfo探了一下,确实没有找到gd的影子.然后检查php.ini,发现gd扩展没有开启(windows下安装的php,其所有php扩 ...
- salvage 数据块打捞工具
基本上所有数据库都是按块存储数据的,每种数据库的块都有自己有特征,我们可以找出特征,当数据库文件丢失,甚至文件系统完全损坏时,从硬盘扇区中把数据页打捞出来,从页从数据页中恢复出行数据.根据这个原理,开 ...
- Percona-Server-5.5.33-31.1安装
一.下载 http://www.percona.com/downloads/Percona-Server-5.5/ Percona-Server-5.5.33-31.1 选择 binary 选择lin ...
- 【转】给Winform的button等控件添加快捷键
ref: http://blog.sina.com.cn/s/blog_4cb9953f0100cy4z.html 第一种:Alt + *(按钮快捷键) 在大家给button.label.menuSt ...
- 新贵HTML5,2016的发展方向会怎样?
2014年下半年,微信捧火了HTML5小游戏,自此国内各行各业开始对HTML5保持高涨关注.2015年是国内HTML5行业迅速发展的一年,在媒体大肆渲染“互联网寒冬”之际,HTML5作品的生产数量和传 ...
- 添加打印机的时候怎样说windows没法连接到打印机毛病为0x00000002
把PrinterExtensionsandNotifications这个服务启动1下试试 PrintSpooler服务停止然后再启用试试
- 淘宝IP地址库API接口(PHP)通过ip获取地址信息
淘宝IP地址库网址:http://ip.taobao.com/ 提供的服务包括: 1. 根据用户提供的IP地址,快速查询出该IP地址所在的地理信息和地理相关的信息,包括国家.省.市和运营商. 2. 用 ...
- Oracle 内核参数
安装Oracle的时候,可以参考Oracle 的安装文档,来设置相关内核参数的值,但是有些参数的值还是需要根据我们自己的情况来进行调整.注:不同系统的参数不同,本篇针对linux. 一.Linux 系 ...
- .NET基础之自定义泛型
在.NET中泛型使用非常频繁,在控制台应用程序中,默认的引入了System.Collection.Generics名称空间,其中就提供了我们经常使用的泛型:List<T>和Dictiona ...
- 域名转化到IP地址的实现
在linux中,有一些函数可以实现主机名和地址的转化,最常见的有gethostbyname().gethostbyaddr()等,它们都可以实现IPv4和IPv6的地址和主机名之间的转化.其中geth ...