1. 怎样表示输入或输出的结束:
1) 都知道TCP通信其实就是用客户端(Socket对象)的socket传递数据的,传递数据都是通过Socket类获取InputStream和OutputStream的;
2) 一般最纠结的就是不知道对方的输出什么时候结束,前面给出的示例都没有处理输出结束(对方)的问题,除非你直接关闭程序否则输出永远都不会结束;
3) 都知道只要关闭输出流就表示输出结束,但是在Socket通信中,一旦输出流被彻底关闭就意味着Socket的关闭,那么网络通信就无法继续了,通常希望关闭输出流之后输入流还可以继续从远程接受数据,或者关闭输入流之后还能通过输出流向远程传送数据;
4) 因此Socket类提供了半关闭的方法:
i. void shutdownOutput(); // 只关闭输出流(但输入流仍然能用)进入半写状态(write-half),通知对方远程输出已经关闭,
ii. void shutdownInput(); // 只关闭输入流(但输出流仍然能用)进入半读状态(read-half),通知对方远程读取已经关闭
!!即使先后调用这两个方法也不会关闭Socket,只不过处于既不能输出也不能输入的废物状态;
!!!上面的方法是半关闭方法,那么彻底关闭输出输入流应该怎么做呢?
a. 通常会对Socket对象调用getInputStream、getOutputStream然后用BufferedReader、PrintStream等包装;
b. 那个包装器就是彻彻底底的输入输出流了,如果调用包装器对象br、ps的close方法那就彻底的关闭输入输出流了;
c. 它们的关闭就意味着Socket也被关闭了!!
!!检查Socket对象是否关闭的方法:boolean Socket.isClosed();
5) 同样Socket类也提供了查看是否处于半读半写状态的方法:
i. boolean isOutputShutdown(); // 是否处于半写状态
ii. boolean isInputShutdown(); // 是否处于半读状态
2. 半关闭适用于哪些场景:
1) 当然是用于那些不需要长久保持通信状态的一站式服务;
2) 特别适用于HTTP通信,而且特别适用于客户端,因为客户端在发送请求后就无需再发送其它数据了,往往只是等待服务器端返回想要的资源;
3) 因此在客户端发送完请求之后就可以立马半关闭输出流了(半写状态);
3. 示例:
public class Server { public static void main(String[] args) throws IOException { // TODO Auto-generated method stub ServerSocket ss = new ServerSocket(30000); Socket s = ss.accept(); PrintStream ps = new PrintStream(s.getOutputStream()); Scanner scan = new Scanner(s.getInputStream()); ps.println("first line"); ps.println("second line"); s.shutdownOutput(); // 如果是ps.close()那么s也就关闭了 System.out.println(s.isClosed()); // false while (scan.hasNextLine()) { System.out.println(scan.nextLine()); // 有输出,说明半关闭 } scan.close(); s.close(); ss.close(); } }