PrintWriter类的println(String x)方法和writer(Stirng x)方法都表示把输入写到输出流中,但需要注意println()方法会再文本的后面加上分隔符,如windows下为“\r\n”,不同操作系统间有区别。println(String x)的实现在源码中为:
public void println(String x) { synchronized (lock) { print(x); println(); } }
其中,println()的源码实现为:newLine();对该方法继续分析发现其实现中包含以下代码:out.write(lineSeparator);也就是向输出流中写入一个lineSeparator,继续深入探寻lineSeparator发现该属性在类PrintWriter的构造方法中被赋值为:
lineSeparator = java.security.AccessController.doPrivileged( new sun.security.action.GetPropertyAction("line.separator"));
可见该属性与系统相关。
writer(String x)方法的最终实现为: out.write(buf, off, len);
其中buf为字符数组,默认大小为1024,当字符串的长度大于1024时,
将使用字符串的长度作为数组容量,该方法将字符串分解成一个个字符然后写入输出流中,
不会写入分隔符。
综上,当服务器端输出流使用writer(String x)方法时,客户端使用Scanner类的hasNextLine()方法和nextLine()方法从输入流中读取数据时,由于nextLine()方法无法读取到行分隔符,该方法将造成阻塞,客户端将不会显示服务器端发来的信息,解决方法:当使用write(String x)时,在字符串后面加上行分隔符“\r\n”,或者使用println(Stirng x)方法。
public class ServerHalfClosed { public static void main(String[] args) { try(ServerSocket serverSocket = new ServerSocket(9000)){ Socket server = null; try { server = serverSocket.accept(); Scanner sc = new Scanner(System.in); PrintWriter pw = new PrintWriter(server.getOutputStream()); String line=null; while ((sc.hasNextLine() && !(line = sc.nextLine()).trim().equals("over"))){ pw.write(line+"\r\n"); //pw.println(line);也可以这样 pw.flush(); } pw.write(line); pw.flush(); server.shutdownOutput(); pw.close(); } finally { if(server!=null) server.close(); } }catch (IOException e) { e.printStackTrace(); } } }以上为服务器端代码。
public class ClientHalfClosed { public static void main(String[] args) { try{ Socket client =new Socket("localhost",9000); Scanner scan = new Scanner(client.getInputStream()); PrintWriter pw = new PrintWriter(client.getOutputStream()); System.out.println("客户端连接上:"+client.getLocalPort()); pw.flush(); client.shutdownOutput(); String line=null; while (scan.hasNextLine()){ if(!(line=scan.nextLine()).trim().equals("over")) System.out.println("客户端收到:"+line+"来自服务端:"+client.getInetAddress().getHostAddress()); } System.out.println("客户端收到:"+line+" ,接收完毕!"); client.shutdownInput(); pw.close(); client.close(); }catch (IOException e){ e.printStackTrace(); } } }以上 为客户端代码。