探讨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)对于我们来说已经不陌生了.对于大型系统来说使用单点登录可以减少用户很多的麻烦.就拿百度来说吧,百度下面有很多的子系统——百度经验.百度知道.百度文库等 ...
随机推荐
- 操作Excel导入的问题(转)
当Excel导入成为需要时,之前的导出Excel为html方式的方法就受阻了,于是,需要开始新的百度与google来解决问题. 前提为OLEDB+Excel. 根据需求,多数是对于表的数据的导入.于是 ...
- 用css3做标签
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 【转载】应读者强烈要求给出《超容易的Linux系统管理入门书》一书的主要知识点
刚开始了一篇连载,收到广大Linux爱好者的反馈,非常欣慰.大家对Linux学习感到很迷茫,不知道学哪些内容,如何学习? <超容易的Linux系统管理入门书>一书是腾讯Linux专家在腾讯 ...
- java集合 collection-list-ArrayList 去除ArrayList集合中的重复元素。
import java.util.*; /* 去除ArrayList集合中的重复元素. */ class ArrayListTest { public static void sop(Object o ...
- L009-oldboy-mysql-dba-lesson09
L009-oldboy-mysql-dba-lesson09 mysql> grant replication salve,replication client on *.* to ‘repl_ ...
- 【转载】GDB反向调试(Reverse Debugging)
记得刚开始学C语言的时候,用vc的F10来调试程序,经常就是一阵狂按,然后一不小心按过了.结果又得从头再来,那时候我就问我的老师,能不能倒退回去几步.我的老师很遗憾地和我说,不行,开弓没有回头箭.这句 ...
- Android Activity 注意笔记
图1:Activity生命周期的简化图,就像一个阶梯金字塔.这图像表明每个状态中是怎么样使用回调函数使得恢复状态回到顶端,或者降低状态到达底部.Activity可以从Paused状态和stopped状 ...
- 1 server - n clients 模型实现(select)
拓扑结构: 各个客户端创建读写管道,通过“上下线信息管道”向服务器发送上下线信息和读写管道名称.服务器接受信息,修改链表(存储客户端信息).客户端.服务器打开读写管道,服务器通过“W”管道接收从客户端 ...
- JavaScript console 用法大全
对于前端开发者来说,在开发过程中需要监控某些表达式或变量的值的时候,用 debugger 会显得过于笨重,取而代之则是会将值输出到控制台上方便调试.最常用的语句就是console.log(expres ...
- MySQL 5.1.63 单机配置多实例(简单配置)
需求: 在一台服务器上通过源码编译安装一个版本为5.1.63版本MySQL数据库: 方案:将所有配置文件与数据等均存放在/home/zhaoshuangshuang下.在同一个MySQL中运行两个实例 ...