有关socket Read

  • 实际开发中,网络程序最可能遇到的就是数据没收到、收到错误数据这样诡异的问题.
  • 很多时候,都是由于对socket read的细节理解的不一致,导致了程序前后的矛盾。
  • 下面详细阐述整个read的过程。

一、从c的角度

ssize_t read(int fd,void *buf,size_t nbyte)

  • read函数是负责从fd中读取内容.
  • 当读成功时, read返回实际所读的字节数
  • 如果返回的值是0 表示已经读到文件的结束了,小于0表示出现了错误。

  • 可以同时检查errno:

  • 如果错误为EINTR(值为4)说明读是由中断引起的
  • 如果是ECONNREST表示网络连接出了问题

二、从协议角度

  • TCP协议是面向流的
  • read和write调用的返回值往往小于参数指定的字节数。
  • 对于read调用,如果接收缓冲区中有20字节,请求读100个字节,就会返回20。
  • 对于write调用,如果请求写100个字节,而发送缓冲区中只有20个字节的空闲位置,那么write会阻塞,直到把100个字节全部交给发送缓冲区才返回,但如果socket文件描述符有O_NONBLOCK标志,则write不阻塞,直接返回20。

三、从java的角度

SocketChannel sc = (SocketChannel) sk.channel(); int i = sc.read(buff)

  • SocketChannel.read 有数据时返回数据长度。
  • 如果返回的值是0 表示已经读到文件的结束了,小于0表示出现了错误(继承自C)。
  • 而linux的函数是针对文件fd出现的定义,如果是网络时,EOF的界限十分模糊。

四、从kernel的角度

static int unix_stream_recvmsg(struct kiocb iocb, struct socket sock, struct msghdr *msg, size_t size, int flags)

  • http://blog.chinaunix.net/uid-23629988-id-3035613.html
  • 这篇文章的主人详细分析了整个过程。
  • 当网卡上没有数据时,返回为0。
  • 另外在对端单独close write或者自己单独close read时,也返回0。
  • 当数据取完了,且出现意外的系统调用,比如网卡故障,返回-1。

五、从java nio的框架角度

  • 结合java nio的selector机制,要对read为0的情况进行统计处理。
  • 同一源过多的read为0,意味着网络不好,或者恶意攻击。


原创文章如转载,请注明:转载自五四陈科学院[http://www.54chen.com]

捐款订阅54chen
捐赠说明