当socketChannel为阻塞方式时(默认就是阻塞方式)read函数,不会返回0,阻塞方式的socketChannel,若没有数据可读,或者缓冲区满了,就会阻塞,直到满足读的条件,所以一般阻塞方式的read是比较简单的,不过阻塞方式的socketChannel的问题也是显而易见的。这里我结合基于NIO 写ftp服务器调试过程中碰到的问题,总结一下非阻塞场景下的read碰到的问题。注意:这里的场景都是基于客户端以阻塞socket的方式发送数据。

1、read什么时候返回-1

read返回-1说明客户端的数据发送完毕,并且主动的close socket。所以在这种场景下,(服务器程序)你需要关闭socketChannel并且取消key,最好是退出当前函数。注意,这个时候服务端要是继续使用该socketChannel进行读操作的话,就会抛出“远程主机强迫关闭一个现有的连接”的IO异常。

2、read什么时候返回0

其实read返回0有3种情况,一是某一时刻socketChannel中当前(注意是当前)没有数据可以读,这时会返回0,其次是bytebuffer的position等于limit了,即bytebuffer的remaining等于0,这个时候也会返回0,最后一种情况就是客户端的数据发送完毕了(注意看后面的程序里有这样子的代码),这个时候客户端想获取服务端的反馈调用了recv函数,若服务端继续read,这个时候就会返回0。

总结:当客户端发送的是文件,而且大小未知的情况,服务端如何判断对方已经发送完毕。如单纯的判断是否等于0,可能会导致客户端发送的数据不完整。所以,这里加了一个检测0出现次数的判断,来判断客户端是否确实是数据发送完毕了,当然这个方法是比较笨拙的方法,大家若有更好的方法,期待大家给我答案。

网上也有类似的建议,比如自定义协议,在数据头部带上文件大小等。

注意:这里有一个问题就是通过这种while循环读取的方式,实际上它只有一次NIO事件通知,而且在这个处理过程中,其他事件就得不到及时处理,除非while结束。

更好的方式是整个体系中只有一个大的bytebuffer封装体,然后每次使用都从这个封装体中去取然后手工释放也就有些人说的“memcache”。

你说这句话的时候已经说明连入门级还没到。多个线程中不同的KEY读取的数据在同一个bytebuffer中交叉存放,然后如果分配给每个具体的处理程序?“手工释放”这种搞笑的话也说得出来?如何手工?用手去操作内存?除了因为理屈词穷而想出这种混乱思维,你说的有些人在哪里见到这种使用方式?

对sk.interestOps(SelectionKey.OP_READ);的两点你说明什么?说明你去看了底层的操作?底层如何操作了?只说明你根本没有能力看懂sk.interestOps(SelectionKey.OP_READ);的作用。

对于非阻塞IO的读操作(写相反),一次select只是通知载协议栈的读操作有数据可读,至于这次读到的数据是多少,是否是一次完整的交互数据,selector并不关心。如果客户端在发送了1024字节的数据,这次只读到512字节,那么余下的512只能等下次select,除非是阻塞方式可以等到一直读完。

那么到底是重新注册READ事件还是sk.interestOps(SelectionKey.OP_READ);,如果重新注册当然可以读到下面的数据,但是你就无法和上次的那部份数据合并,因为多个KEY的不完整数据同时存在,你不知道要合并到哪个现有上去,所以用sk.interestOps(SelectionKey.OP_READ);的意思其实就是用同一个KEY重新注册,下次读到的余下的数据合并到上次这个KEY的部分数据上,代表同一客户端的一次完整的发送。

对于同一次交互中比较大的数据,必须使用sk.interestOps(SelectionKey.OP_READ);来多次读取。无论你出于什么原因只要你知道他的作用就不可能说它不必要。就象阻塞方法中我们while((len = in.read(buf)) > 0){....};如果你说while不必要的话,那只能说明你根本不懂IO操作。

理论上即使对方发两个字节的数据,一次select也可能只读到第一个字节,除非在第一次select时,已经读到的数据中包含中约定好的结束标记或已经知道的长度。而楼主的代码只是将读到的数据打印出来,既没有判断是否已经读到结束标记,也没判断已经读到的数据长度是否达到多少而不需再读,那么sk.interestOps(SelectionKey.OP_READ);来读下次数据怎么会不必要?只要你懂这段代码的意思就不可能说出这样的话。说出这样的话只能代表你不懂

服务端的代码(客户端发送的数据大小未知)

[java] view plaincopy
  1. import java.io.IOException;
  2. import java.nio.ByteBuffer;
  3. import java.nio.channels.SelectionKey;
  4. import java.nio.channels.Selector;
  5. import java.nio.channels.SocketChannel;
  6. import com.myftpnio.server.FtpNioServer;
  7. public class ClientHandler implements NioHandler {
  8. private SocketChannel sc;
  9. @SuppressWarnings("unused")
  10. private Selector selector;
  11. private ByteBuffer buf = ByteBuffer.allocate(1024);
  12. private long sum = 0;
  13. private static int count_zore = 0;
  14. public ClientHandler(SocketChannel sc, Selector selector) {
  15. this.sc = sc;
  16. this.selector = selector;
  17. }
  18. @Override
  19. public void execute(SelectionKey key) {
  20. // TODO Auto-generated method stub
  21. if (key.isReadable()) {
  22. try {
  23. while(true) {
  24. buf.clear();
  25. int n = sc.read(buf);
  26. if (n > 0) {
  27. sum += n;
  28. System.out.println("sum=" + sum + " n=" + n + " " + FtpNioServer.ByteBufferToString(buf));
  29. } else if (n == 0) {
  30. if (count_zore++ < FtpNioServer.MAX) {
  31. continue;  //这里表明还需要读取数据
  32. } else {
  33. key.interestOps(SelectionKey.OP_WRITE);
  34. break;  //这里表明已经读取到了所有需要的数据
  35. }
  36. } else if (n == -1) {
  37. System.out.println("client close connect");
  38. sc.close();
  39. key.cancel();
  40. return;
  41. }
  42. }
  43. } catch (IOException e) {
  44. //处理捕获到的IO异常
  45. System.out.println(e.getMessage());
  46. try {
  47. sc.close();
  48. } catch (IOException e1) {
  49. // TODO Auto-generated catch block
  50. e1.printStackTrace();
  51. }
  52. key.cancel();
  53. return;
  54. }
  55. }
  56. if (key.isWritable()) {
  57. try {
  58. String ret = "hello " + sc.socket().getRemoteSocketAddress().toString();
  59. ByteBuffer send = ByteBuffer.wrap(ret.getBytes());
  60. sc.write(send);
  61. key.cancel();
  62. sc.close();
  63. FtpNioServer.connum--;
  64. count_zore = 0;
  65. } catch (Exception e) {
  66. e.printStackTrace();
  67. }
  68. }
  69. }
  70. }

java nio socketChannel read返回值代表的意思相关推荐

  1. java方法带参数返回值_Java方法中的参数太多,第6部分:方法返回

    java方法带参数返回值 在当前的系列文章中,我正在致力于减少调用Java方法和构造函数所需的参数数量,到目前为止,我一直专注于直接影响参数本身的方法( 自定义类型 , 参数对象 , 构建器模式 , ...

  2. Java NIO SocketChannel+Buffer+Selector 详解(含多人聊天室实例)

    一.Java NIO 的核心组件 Java NIO的核心组件包括:Channel(通道),Buffer(缓冲区),Selector(选择器),其中Channel和Buffer比较好理解  简单来说 N ...

  3. java 参数返回_Java基础---Java中带参数返回值方法的使用(四十)

    Java 中带参带返回值方法的使用 如果方法既包含参数,又带有返回值,我们称为带参带返回值的方法. 例如:下面的代码,定义了一个 show 方法,带有一个参数 name ,方法执行后返回一个 Stri ...

  4. Java中使用有返回值的线程

    在创建多线程程序的时候,我们常实现Runnable接口,Runnable没有返回值,要想获得返回值,Java5提供了一个新的接口Callable,可以获取线程中的返回值,但是获取线程的返回值的时候,需 ...

  5. java 异步得到函数返回值_使用JavaScript进行异步编程

    毫无疑问,虽然JavaScript的历史比较悠久,但这并不妨碍它成为当今最受欢迎的编程语言之一.对刚接触该语言的人来说,JavaScript的异步特性可能会有一些挑战.在本文中,我们将了解和使用Pro ...

  6. java字符类型的返回值,Java字符类isWhitespace()方法及示例

    Character 类isWhitespace()法isWhitespace()方法在java.lang包中可用. isWhitespace()方法用于检查给定的char值是否为空格,但是它包含空格中 ...

  7. Java基础---Java中带参数返回值方法的使用(四十)

    Java 中带参带返回值方法的使用 如果方法既包含参数,又带有返回值,我们称为带参带返回值的方法. 例如:下面的代码,定义了一个 show 方法,带有一个参数 name ,方法执行后返回一个 Stri ...

  8. Java NIO SocketChannel读

    以读取百度的首页内容为例: import java.net.InetAddress; import java.net.InetSocketAddress; import java.nio.ByteBu ...

  9. java的main函数返回值_Java中的main方法

    首先需要说明的是: 1.main函数(主函数)是可以调用的,这种调用是没有意义的: 2. main函数只能出现在公共类中也就是public class中: 但我不明白的是:在eclipse中默认的in ...

最新文章

  1. log4j打印mybatis sql语句
  2. 利用nofllow与内页链接做好SEO
  3. 开发高性能并发应用不是一件容易的事情。这类应用的例子包括高性能Web服务器、游戏服务器和搜索引擎爬虫...
  4. iOS使用UIBezierPath实现ProgressView
  5. 程序员面试100题之十六:二叉树中两个节点的最近公共父节点(最低的二叉树共同祖先)
  6. 第一章 数据挖掘基础
  7. java ltp4j_43、哈工大NLP自然语言处理,LTP4j的测试+还是测试
  8. 001-spring结合quartz使用
  9. 今天聊:做好前端的 10 个习惯
  10. exchange邮箱账号禁用之后 启用方法
  11. 图片加载------reactVirtualized
  12. Atlas学习手记(21):使用行为增强用户界面(一):Click Behavior
  13. Python转换图片格式 -- PIL库的使用
  14. 2022年1月舆情信息事件分析总结报告
  15. 离散数学真值表c语言实验报告,离散数学五人表决真值表实验报告
  16. Java 导出word和pdf_Java实现word导出与pdf导出
  17. 考研失败最根本的5个原因!
  18. c语言变量 集体备课,(最新整理)数学集体备课活动记录2
  19. 【数据分析】- 游戏业务常用指标
  20. CTFshowWeb入门nodejs

热门文章

  1. Office 365最新2022新版本
  2. 打卡第二天 树形DP初步
  3. 黑科技|感官世界与人机交互的盛宴 --未来虚拟现实养成记
  4. LTE协议之用户面与控制面UE侧协议结构
  5. 2022年 微前端技术调研- 图文并茂
  6. canvas制作旋转的太极图
  7. 关于 Spfile文件误删除 或者 优化错误 恢复
  8. 【芝麻背调百科】上午刚发offer,下午老板竟说不要了!HR怎么办?
  9. 旅行商问题以及python实现
  10. 基于H5canvas和js的高斯模糊处理