探讨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)对于我们来说已经不陌生了.对于大型系统来说使用单点登录可以减少用户很多的麻烦.就拿百度来说吧,百度下面有很多的子系统——百度经验.百度知道.百度文库等 ...
随机推荐
- CSS常见的浏览器前缀
为了让浏览器识别某些专属属性,有时候需要在CSS属性前增加浏览器前缀 -ms-:Microsoft IE -moz-:Mozilla Firefox -o-:Opera Opera -webkit-: ...
- 使用C#通过调用minitab的COM库自动化生成报表
本文介绍通过C#调用minitab com组建自动化生成报表的方法. 首先需要在minitab中通过手动配置的方式生成报表来得到该报表的命令行,过程如下 选择菜单“编辑器”->“启用命令”启用命 ...
- 关键字 explicit
C++中, 一个参数的构造函数(或者除了第一个参数外其余参数都有默认值的多参构造函数), 承担了两个角色. 1 是个构造器 ,2 是个默认且隐含的类型转换操作符. 所以, 有时候在我们写下如 AAA ...
- fopen vs fsocketopen vs curl
http://stackoverflow.com/questions/2647170/curl-vs-fopen-vs-fsocketopen http://stackoverflow.com/que ...
- offset() position() scrollTop() scrollLeft()
(1)offset:获取当前元素相对于文档的高度.只对可见元素有效. 不管该元素如何定位,也不管其父元素如何定位,都是获取的该元素相对于当前视口的偏移 (2) position:获取元素相对于最近的一 ...
- CocoaPods安装和使用及问题:Setting up CocoaPods master repo
CocoaPods是什么? 当你开发iOS应用时,会经常使用到很多第三方开源类库,比如JSONKit,AFNetWorking等等.可能某个类库又用到其他类库,所以要使用它,必须得另外下载其他类库,而 ...
- C#让TopMost窗体弹出并置顶层但不获取当前输入焦点的终极办法
为了使程序在弹出窗口时置顶层且不获取系统输入焦点,避免影响用户当前的操作,来电通来电弹屏软件尝试过N多种办法,例如:弹出前保存当前焦点窗口句柄,弹出时因为使用TopMost系统默认将焦点交给了弹出窗口 ...
- NoSQL专家王涛访谈:为什么我们还要做一个NoSQL?
ChinaUnix:各位网友大家好,今天有幸请到王涛先生到CU做客,与大家交流一些工作经验.首先请王涛先介绍一下自己. 王涛:大家好,我是王涛.过去八年里我一直在IBM多伦多实验室从事DB2引擎研发的 ...
- Oracle中NULL值与索引
NULL值是关系数据库系统布尔型(true,false,unknown)中比较特殊类型的一种值,通常称为UNKNOWN或空值,即是未知的,不确定的.由于NULL存在着无数的可能,因此NULL值也不等于 ...
- 在虚拟中开启Windows 8.1的Hyper-V平台
VM安装windows8开启Hype-V 今天老魏用VM安装了Windows8.1系统,想用此系统来开发一下Windows Phone8,但是要求确实要开启Hyper-V平台技术,本来是没有任何的问题 ...