黑马程序员技术交流社区

标题: 关于readLine()方法 [打印本页]

作者: mengxiang1993    时间: 2015-2-4 23:04
标题: 关于readLine()方法
在java基础视频教程网络编程TCP 第23天-13      首先客户端向服务器端写数据,客户端代码如下
                //从键盘读数据
                BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
                //将数据写入到socket流的输出流,发送给服务器端
                BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
                String line=null;
                while((line=br.readLine())!=null){
                        bw.write(line);
                        //输出一个换行
                        bw.newLine();
                        bw.flush();
                }

      毕老师提到服务器端没有读到数据有两点原因:
   一:没有刷新缓冲区,也就是必须写 bw.flush();
   二: 必须输出一个换行,服务器端的readLine()方法必须读到回车符才会返回数据
两点疑问:1.我们在控制台不是都按回车了吗,那个回车服务器端读不到吗?
                  2.在java中回车是不是代表一次数据的录入结束,即一按回车数据才发送出去?

客户端完整代码如下
  1. /**
  2. * 需求:1.键盘读取字符,并发送到服务器端。 2.由服务器端将字符转换成大写字符,返回给客户端。 3.客户端读取数据,打印
  3. * 4.当客户端输出over,转换结束,关闭资源
  4. *
  5. * 步骤:1. 建立socket服务,指定要连接的主机和端口。 2. 通过IO读取键盘录入 3.
  6. * 通过socket流中的输出流,将数据写入到该流中,通过网络发送到服务器端 4. 通过socket流中的输入流,读取从服务器端返回的数据,打印 5.
  7. * 当输出over时,转换结束 6. 关闭资源
  8. */

  9. public class TCPClient {

  10.         public static void main(String[] args) throws UnknownHostException,
  11.                         IOException {
  12.                 // 1.建立socket服务,指定要连接的主机和端口
  13.                 Socket s = new Socket("localhost", 10009);
  14.                 // 2.通过IO读取键盘录入
  15.                 BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
  16.                 // 3.获取socket流中的输出流
  17.                 BufferedWriter bwOut = new BufferedWriter(new OutputStreamWriter(
  18.                                 s.getOutputStream()));
  19.                 // 4.获取socket流中的输入流
  20.                 BufferedReader brIn = new BufferedReader(new InputStreamReader(
  21.                                 s.getInputStream()));
  22.                 // 定义一行数据
  23.                 String line = null;
  24.                 // 写字符到服务器端,从服务器端读返回的大写字符
  25.                 while ((line = br.readLine()) != null) {
  26.                         // 键盘读到over,转换结束
  27.                         if (line.equals("over")) {
  28.                                 break;
  29.                         }

  30.                         bwOut.write(line);
  31.                         // 输出一个回车符
  32.                         bwOut.newLine();
  33.                         // 刷新缓冲区
  34.                         bwOut.flush();

  35.                         String str = brIn.readLine();
  36.                         System.out.println(str);

  37.                 }
  38.                 // 5.关闭资源
  39.                 br.close();
  40.                 // close后在socket流中加了一个-1,告诉服务端的readLine()方法,readLine()方法里面也调用的是read方法,所以遇到-1结束。
  41.                 //当然也可以在服务器端的while循环里对over进行判断。
  42.                 s.close();

  43.         }

  44. }
复制代码




作者: lwh316658735    时间: 2015-2-5 02:00
readLine()读取到'\r'或者\n'时就终止了。
用read读的话会读取回车
作者: mengxiang1993    时间: 2015-2-5 07:23
lwh316658735 发表于 2015-2-5 02:00
readLine()读取到'\r'或者\n'时就终止了。
用read读的话会读取回车

你看看毕向东老师讲的readLine()原理,读到\r会继续读,但是不会把\r返回,直到读到\n才返回\n以前的数据
作者: 肌肉男小虎    时间: 2015-2-5 07:43
还有一点,readLine的话,是读取到\r\n到n的时候返回n之前的,不包括r,但是,存储缓冲区的话,如果不写好的话,能够覆盖的
作者: mengxiang1993    时间: 2015-2-5 08:33
肌肉男小虎 发表于 2015-2-5 07:43
还有一点,readLine的话,是读取到\r\n到n的时候返回n之前的,不包括r,但是,存储缓冲区的话,如果不写好 ...

按回车就是\r\n啊,为什么还要在缓冲区写入\r\n?
作者: qiuyuhuaihua    时间: 2015-2-5 10:07
readLine()方法的原理其实就是掉用了reas()方法,而read()方法是可以把所有的字符都读取出来的,readLine()的特性就是通过循环调用read()方法,直到read()读取到换行符(windows和Linux的不同)停止读取,并且将读取到的除了换行符以外的所有字符写入缓冲区,接着就要调用flush()方法来清空了,这个不多说。由上面说的就可以看到,客户端发出去的数据里面是没有换行符的,如果客户端不添加newLine()方法,那么服务端的readLine()方法在调用read()方法时永远不会读到换行符,那么服务端的 line = bufr.readLine() 会一直接收客户端发来的数据,“根本停不下来”!
作者: mengxiang1993    时间: 2015-2-5 10:26
qiuyuhuaihua 发表于 2015-2-5 10:07
readLine()方法的原理其实就是掉用了reas()方法,而read()方法是可以把所有的字符都读取出来的,readLine() ...

按回车后表示数据录入结束,回车就是\r\n啊
作者: mengxiang1993    时间: 2015-2-5 11:29
mengxiang1993 发表于 2015-2-5 10:26
按回车后表示数据录入结束,回车就是\r\n啊
  1. bwOut.write(line);
  2.                         // 输出一个回车符
  3.                         bwOut.newLine();
  4.                         // 刷新缓冲区
  5.                         bwOut.flush();
复制代码

既然按回车就可以,那就没必要写这行代码  bwOut.newLine();,但是不写,服务端收不到数据,不明白为什么
作者: franksight    时间: 2015-2-5 11:30
就是6楼说的。。。
作者: lwh316658735    时间: 2015-2-5 16:31
mengxiang1993 发表于 2015-2-5 07:23
你看看毕向东老师讲的readLine()原理,读到\r会继续读,但是不会把\r返回,直到读到\n才返回\n以前的数据 ...

你可以去看看API
作者: lwh316658735    时间: 2015-2-5 16:35
mengxiang1993 发表于 2015-2-5 07:23
你看看毕向东老师讲的readLine()原理,读到\r会继续读,但是不会把\r返回,直到读到\n才返回\n以前的数据 ...

读取一个文本行。通过下列字符之一即可认为某行已终止:换行 ('\n')、回车 ('\r') 或回车后直接跟着换行。

上面是API的原话,视频固然重要,但是API才是最核心的再结合着源码看基本没什么问题了。
作者: kfcka    时间: 2015-2-5 17:35
输出流用PrintWriter就不会有这个问题了
作者: 肌肉男小虎    时间: 2015-2-5 23:18
mengxiang1993 发表于 2015-2-5 08:33
按回车就是\r\n啊,为什么还要在缓冲区写入\r\n?

缓冲区没必要写,我说的你没懂,回车是\r\n,但是,你一按回车,那么读取的就是\r\n,懂么
作者: mengxiang1993    时间: 2015-2-6 10:09
嗯嗯,谢谢各位,我已经明白了,从键盘上读取的内容里面是回车前面的内容,所以服务器端要将这段内容发送到客户端,就必须加上换行,客户端读到换行,才返回‘\r\n’前面的内容。




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