探讨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)对于我们来说已经不陌生了.对于大型系统来说使用单点登录可以减少用户很多的麻烦.就拿百度来说吧,百度下面有很多的子系统——百度经验.百度知道.百度文库等 ...
随机推荐
- UVALive 3027(并查集)
题意:某公司的各企业群要建立联系,I i j 表示企业i与企业j建立联系,并且以企业j为中心(并查集中的父亲)(企业j为暂时的中心企业),E i 表示查询企业 i 距离此时的中心企业的距离.各企业间的 ...
- L007-oldboy-mysql-dba-lesson07
L007-oldboy-mysql-dba-lesson07 [root@web01 ~]# mysqldump -uroot -ptestpassword -A >/root/mysql_ba ...
- qml自定义标题栏
要实现自定义的标题栏只需在原来的窗口的基础上创建一个Rectangle并将其定位在窗口顶部即可,实现代码如下: ApplicationWindow { id: mainWindow visible: ...
- response返回随笔
response.setHeader("Content-type", "text/html;charset=UTF-8");//这句话的意思,是让浏览器用utf ...
- nginx 配置文件
#基于ip设置 server{ listen 80; server_name 192.168.116.129; location /{ root /usr/etc/ngin/html/ip; inde ...
- 认识HTML5
引言,认识两个标准制定的组织 在讲什么是Html5之前得先了解两个组织:WHATWG :网页超文本技术工作小组(英语:Web Hypertext Application Technology Work ...
- Android 核心组件 Activity 之下
创建新的Activity的方式: 1. 在相应的文件下 Ctrl + N (Eclipse, Android中不知道是不是) 2. 创建类,继承自Activity或者Activity的子孙类, 并在 ...
- 连续改变Chrome浏览器窗口大小,可以导致内存泄漏
最近在做响应式布局的页面,在开发测试过程中,为了看到页面在不同尺寸的窗口中的表现,因此要不停的拖动浏览器来改变其窗口大小:开始在Chrome浏览器下查看页面,拖动了几次,感觉电脑明显的卡了下来,刚开没 ...
- 就谈个py 的装饰器 decorator
很早很早就知道有这么个 装饰器的东西,叫的非常神秘. 包括c# 和 java 中都有这个东西, c#中叫做attribut 特性,java中叫做Annotation 注解,在偷偷学习c#教程的时候, ...
- JavaScript 权威指南第6版 - [阅读笔记]
JavaScript 基础 Page 13 (1)<script> 的属性:async,charset,defer='defer',language已废,src,type (2)n ...