- 实际开发中,网络程序最可能遇到的就是数据没收到、收到错误数据这样诡异的问题.
- 很多时候,都是由于对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]
捐赠说明