黑马程序员技术交流社区

标题: TCP传输:缓冲区刷新的问题 [打印本页]

作者: 周素强    时间: 2012-5-8 21:12
标题: TCP传输:缓冲区刷新的问题
本帖最后由 周素强 于 2012-5-8 21:14 编辑
  1. /*TCP字符流*//*代码功能描述:向服务端发送字符并接收服务端返回的字符*/
  2. class TransClient//客户端
  3. {
  4. public static void main(String[] args) throws Exception
  5. {
  6. Socket s = new Socket("192.168.1.100",10006);//建立客户端
  7. BufferedReader bufr =
  8. new BufferedReader(new InputStreamReader(System.in));//键盘输入
  9. BufferedReader bufIn =
  10. new BufferedReader(new InputStreamReader(s.getInputStream()));//获取客户端输入流
  11. BufferedWriter bufOut =
  12. new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));//获取服务端输出流
  13. String line = null;//定义变量存储键盘输入数据
  14. while((line=bufr.readLine())!=null)
  15. {
  16. if("over".equals(line))
  17. break;
  18. bufOut.write(line);//向服务端发送数据
  19. bufOut.newLine();//添加结束标记回车符
  20. bufOut.flush();
  21. String str = bufIn.readLine();//获取服务端传过来的大写数据
  22. System.out.println("Server:"+str);
  23. }
  24. bufr.close();
  25. s.close();
  26. }
  27. }
复制代码
  1. /*TCP字节流*//*代码功能描述:TCP传输上传图片*/
  2. import java.io.*;
  3. import java.net.*;

  4. class TcpPicClient //客户端
  5. {
  6. public static void main(String[] args)throws Exception
  7. {
  8. Socket s = new Socket("192.168.1.100",10007);//定义客户端并设置要连接主机的IP和端口
  9. File file = new File("1.png");//定义一个文件对象
  10. BufferedInputStream bufi = new BufferedInputStream(new FileInputStream(file));//创建一个数据源读取流
  11. BufferedOutputStream bufo = new BufferedOutputStream(s.getOutputStream());//获取客户端输出流,以便将数据传送出去
  12. byte[] by = new byte[1024];//定义一个字节缓冲区
  13. int len = 0;
  14. while((len=bufi.read(by))!=-1)
  15. {
  16. bufo.write(by,0,len);//将读取到的数据发送给服务端
  17. //bufo.flush();
  18. }
  19. s.shutdownOutput();//关闭输出流向服务端发送结束标记
  20. bufi.close();
  21. BufferedReader bufr = new BufferedReader(new InputStreamReader(s.getInputStream()));//获取客户端的输入流,以便接收服务端的回复信息
  22. String str = bufr.readLine();//读取服务端发来的信息
  23. System.out.println(str);
  24. s.close();
  25. }
  26. }
复制代码
我有点疑惑的是操作字符流时向服务端发送数据必需得刷新,而操作字节流时就不用刷新,请问这是为什么呢?

作者: 黑马-王建雨    时间: 2012-5-8 21:57
Java中只有输出流才需要刷新缓冲区.
缓冲区:存在的原因是为了维持内存与输入输出设备的速度不匹配。
程序执行时可以先将数据拷贝至缓冲区,一定情形下将数据传给设备。
刷新就是将当前缓冲区数据全部提交。
不刷新时,程序在崩溃时缓冲区内容无法输出(有些情形会带来错误).

作者: 张小锋    时间: 2012-5-8 22:19
我个人觉的操作字符流和操作字节流只要使用了缓冲流都要刷新啊,
不过如果不使用flush,那么就不要在忘了使用close方法,因为流关闭之前会自动调用flush方法。
尽管如此每次使用流完毕后先使用flush,在close,这也要养成习惯,以免造成不必要的数据丢失
如果既没有使用flush,也没有关闭流,那么你最后一次读取的数据就暂时存放在缓冲区中,并没有写入硬件设备上,只要调用flush() 或者close()即可,这是把缓冲区的数据手动写入文件。

作者: 周素强    时间: 2012-5-8 23:38
啷个里个郞 发表于 2012-5-8 21:57
Java中只有输出流才需要刷新缓冲区.
缓冲区:存在的原因是为了维持内存与输入输出设备的速度不匹配。
程 ...

恩,这个我知道,我问的是为什么字节输出流时不用刷新呢?你再看一下我的两个程序都是输出流在操作数据向服务端提交
作者: 周素强    时间: 2012-5-8 23:39
张小锋 发表于 2012-5-8 22:19
我个人觉的操作字符流和操作字节流只要使用了缓冲流都要刷新啊,
不过如果不使用flush,那么就不要在忘了使 ...

我明白,我问的是为什么字节可以不刷新就能保存数据,而字符的不可以呢?
作者: 张小锋    时间: 2012-5-9 02:30
你的这个问题我也不敢确定,只是冒昧猜测了一下,还待证实,如有不对请见谅:

BufferedWriter是继承Writer的,Java API里是说Write()和append()一样,请看API:
public Writer append (CharSequence csq)
Appends the character sequence csq to the target. This method works the same way as Writer.write(csq.toString()). If csq is null, then the string "null" is written to the target stream.

根据经验我们一般在使用在使用字符串缓冲类StringBuffer和StringBuilder时才会用到append方法,所以我估计他们之间多少会有些关联,

可能当new BufferedWriter()时产生的效果和new StringBuffer()差不多,既然API介绍说BufferedWriter的write方法和append方法一样,我猜想调用write方法时,虚拟机会直接将新的字符串追

加到内存的字符串池中以前的字符串后面,就和StringBuffer的append原理一样,write仅仅只改变了内存中的字符串,并没有真正的写入硬件设备上,

由于StringBuffer字符串缓冲区的容量是自动增长的,BufferedWriter的缓冲区也会自动增长。

所以这就是如果不使用flush方法或close方法,缓冲区里的数据就一直留在内存中。

以上仅仅是猜测,未经证实,网上查了很多次,很难找到BufferedWriter类中的write的解释,如有不足,请斧正!




作者: 张小锋    时间: 2012-5-9 02:39
   

在补上一点:


BufferedWriter使用的的是字符串缓冲,缓冲区容量可能也是自动增张的,使用Write方法会一直不断的向缓冲区里追加新字符串,因为其容量永远满不了,

不像使用数组作为缓冲那样有固定容量,超过容量限制后,write方法会自动将缓冲区里的数据写入到硬件设备上,而BufferedWriter没有这个功能。




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2