A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© x378320002 中级黑马   /  2013-7-3 19:11  /  2132 人查看  /  12 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 x378320002 于 2013-7-4 10:28 编辑

IO流中有read()方法,哪个高手能解释下它是怎么判断这个方法结束的?
文档里只是说在输入数据可用、检测到文件末尾或者抛出异常前,就一直阻塞。
查看源代码是本地代码,看不了,估计看到了也看不懂,不太精通c、c++。
就是输入流怎么知道数据可不可用,是不是流末尾的?

就像毕老师讲课中的模拟浏览器给tomcat发信息的例子
  1.   Socket s = new Socket("192.168.1.100",8080);
  2.                
  3.                 //模拟浏览器,给tomcat服务端发送符合http协议的请求消息。
  4.                 PrintWriter out = new PrintWriter(s.getOutputStream(),true);
  5.                 out.println("GET /myweb/1.html HTTP/1.1");
  6.                 out.println("Accept: */*");
  7.                 out.println("Host: 192.168.1.100:8080");
  8.                 out.println("Connection: close");
  9.                 out.println();
  10.                 out.println();
  11.                
  12.                 InputStream in = s.getInputStream();

  13.                 byte[] buf = new byte[1024];
  14.                 int len = in.read(buf);
复制代码
并没有给tomcat发送什么结束信息,tomcat那边的读方法为什么不一直阻塞?

还有我自己写的一个上传图片的程序,先上传图片名字,再上传图片的,客户端
  1. //                先发送名字过去---------
  2.                 OutputStream fout=s.getOutputStream();
  3.                 fout.write(f.getName().getBytes());
  4. //                在发送内容过去
  5.                 byte[] barr=new byte[1024];
  6.                 int len=0;
  7.                 while((len=fin.read(barr))!=-1){
  8.                         fout.write(barr, 0, len);
  9.                 }
复制代码
服务端部分代码
  1. //                        从socket读取文件名字
  2.                         InputStream in = s.getInputStream();
  3.                         byte[] barr = new byte[1024];
  4.                         int len = in.read(barr);    //--------------这里为什么没有阻塞?
  5.                         String name = new String(barr, 0, len);
复制代码
我觉得这里的客户端那发送名字和发送内容几乎没有间隔,应该是不行的,我认为服务器端的int len = in.read(barr);在接收到
名字的数据后会继续阻塞,因为ta但是实际并没有,在接受到名字字符串后就直接建立了文件。






评分

参与人数 1技术分 +1 收起 理由
杜光 + 1 每天提问并回答问题,是对知识的复习和积累.

查看全部评分

12 个回复

倒序浏览

回帖奖励 +1

本帖最后由 王磊 于 2013-7-3 21:52 编辑

第一个tomcat的例子里,服务器那端没有堵塞是因为已经读到了数据的末尾,这个数据末尾就是客户端发送的请求消息的全部内容都写出完毕,没有数据可写时,就会相当于给服务端写了一个结束的指令,也可以说是服务端没有读到数据,则read方法返回的结果就是-1。这就好像在写一个读取流读一个硬盘文件一样,当read将文件的数据全部读取完毕,最后一次读取的时候没有数据可读,就会收到一个-1的返回值,这样就会判断读取结束。
至于第二个例子,没有阻塞是因为read是一次读取指令,并不是放在循环里,这样客户端发写出的数据一定会被服务端的read方法将缓冲数组写满,一旦写满就意味着这条read执行完毕,楼主说的阻塞情况,一般只有两种情况能发生,一种是read在循环内,一种就是另一边根本就没有写出数据来让read进行读取。

顺便还想看下楼主第二个例子的服务端后续的代码是怎么写的。

评分

参与人数 1黑马币 +3 收起 理由
杨兴庭 + 3

查看全部评分

回复 使用道具 举报 1 0

回帖奖励 +1

我是来拿金币的

评分

参与人数 1黑马币 +1 收起 理由
杨兴庭 + 1 给你金币,接好

查看全部评分

回复 使用道具 举报

回帖奖励 +1

为了更好的维护论坛的学习氛围,如果您的的问题“已经解决”请即时将帖子状态改成“已解决”

-------------------坚持学习,黑马因你而精彩---------------
回复 使用道具 举报
本帖最后由 x378320002 于 2013-7-4 11:08 编辑
王磊 发表于 2013-7-3 21:46
第一个tomcat的例子里,服务器那端没有堵塞是因为已经读到了数据的末尾,这个数据末尾就是客户端发送的请求 ...

”这个数据末尾就是客户端发送的请求消息的全部内容都写出完毕,没有数据可写时,就会相当于给服务端写了一个结束的指令“,但是我们并没有显示的发出数据末尾指令啊,是系统自动发的么?如果有的话,客户端这边发末尾指令的标准是什么呢,就像如果客户端发的数据不是连续的,中间隔了几句话,或者Cpu写完第一句去忙别的了,过一会来写第二句,服务端那边不会还等着它回来写末尾指令吧,我推测的是read往数组读取数据但还没有填满数组时可能每次读到空,都会临时阻塞很小一小段时间,以判断真的是没有数据了,如果数组中没有任何数据,则一直阻塞,如果数组中有至少一个数据,则返回数据个数结束本次读取。这个也是猜测,因为我发现我这个例子服务端的那个read(barr)读取的数据并不是每次都一样的,有时候是只有名字那几个字节,并不是每次都会填满,有时候是就会读满。但是在发送名字过去后让线程停止几毫秒,服务端就会非常稳定每次只都读取名字的20字节。
               OutputStream fout=s.getOutputStream();
                fout.write(f.getName().getBytes());
                Thread.sleep(10)    //让线程睡觉---------
//              在发送内容过去
                byte[] barr=new byte[1024];

你 说的读取一个硬盘文件的好理解,因为那个流在创建时就关联的文件,知道文件的结尾也就是流的结尾在哪里,到时候返回-1就行,而在socket里,里面随时都可能被写入数据,哪怕几句println数据也有可能并不是一次性写入,在没有人为写入结束标记的情况下,它怎么结束的,万一它刚结束对面还有数据要写入呢。

我那个后续代码是这样的
  1.                 String name = new String(barr, 0, len);

  2.                         File f = new File("G:\\" + name);
  3.                         if (!f.exists()) {
  4.                                 f.createNewFile();
  5.                         }

  6.                         FileOutputStream fout = new FileOutputStream(f);
  7.                         
  8.                         while ((len = in.read(barr)) != -1) {
  9.                                 fout.write(barr, 0, len);
  10.                         }
  11.                
  12.                         PrintWriter pw = new PrintWriter(s.getOutputStream(), true);
  13.                         pw.println("上传成功");

  14.                         fout.close();
  15.                         s.close();
  16.                 } catch (IOException e) {
  17.                         e.printStackTrace();
  18.                 }
  19.         }
复制代码
回复 使用道具 举报

回帖奖励 +1

:)学习一下
回复 使用道具 举报

回帖奖励 +1

学习一下!!!
回复 使用道具 举报

回帖奖励 +1

我是来学习的
回复 使用道具 举报

回帖奖励 +1

好深奥的样子
回复 使用道具 举报
时过境迁。。。。。。。。。
回复 使用道具 举报

回帖奖励 +1

学习一下。。。
回复 使用道具 举报

回帖奖励 +1

学习了!
回复 使用道具 举报

回帖奖励 +1

学习一下。。。
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马