### 服务器端 ```java package com.wang5; import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.nio.charset.StandardCharsets; /** * @ File : Server.java * @ Author : Wangyuedong * @ Time : 2021/9/13 16:56 */ public class Server { public static void main(String[] args) throws IOException { ServerSocket ss = new ServerSocket(6666); //监听6666端口 System.out.println("Server is running..."); for(;;){ Socket sock = ss.accept(); System.out.println("connected from " + sock.getRemoteSocketAddress()); Thread t = new Handler(sock); t.start(); } } } class Handler extends Thread { Socket sock; public Handler(Socket sock) { this.sock = sock; } @Override public void run() { try (InputStream input = this.sock.getInputStream()) { try (OutputStream output = this.sock.getOutputStream()) { handle(input, output); } } catch (Exception e) { try { this.sock.close(); } catch (IOException ioe) { } System.out.println("client disconnected."); } } private void handle(InputStream input, OutputStream output) throws IOException { BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(output, StandardCharsets.UTF_8)); BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8)); writer.write("hello\n"); writer.flush(); for (;;) { String s = reader.readLine(); if (s.equals("bye")) { writer.write("bye\n"); writer.flush(); break; } writer.write("ok: " + s + "\n"); writer.flush(); } } } ``` ### 客户端 ```java package com.wang5; import java.util.Scanner; import java.io.*; import java.net.Socket; import java.nio.charset.StandardCharsets; /** * @ File : Client.java * @ Author : Wangyuedong * @ Time : 2021/9/13 17:08 */ public class Client { public static void main(String[] args) throws IOException { Socket sock = new Socket("localhost", 6666); // 连接指定服务器和端口 try (InputStream input = sock.getInputStream()) { try (OutputStream output = sock.getOutputStream()) { handle(input, output); } } sock.close(); System.out.println("disconnected."); } private static void handle(InputStream input, OutputStream output) throws IOException { BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(output, StandardCharsets.UTF_8)); BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8)); Scanner scanner = new Scanner(System.in); System.out.println("[server] " + reader.readLine()); for (;;) { System.out.print(">>> "); // 打印提示 String s = scanner.nextLine(); // 读取一行输入 writer.write(s); writer.newLine(); writer.flush(); String resp = reader.readLine(); System.out.println("<<< " + resp); if (resp.equals("bye")) { break; } } } } ``` ### Socket流 当Socket连接创建成功后,无论是服务器端,还是客户端,我们都使用`Socket`实例进行网络通信。因为TCP是一种基于流的协议,因此,Java标准库使用`InputStream`和`OutputStream`来封装Socket的数据流,这样我们使用Socket的流,和普通IO流类似。 ```java // 用于读取网络数据: InputStream in = sock.getInputStream(); // 用于写入网络数据: OutputStream out = sock.getOutputStream(); ``` 如果不调用`flush()`,我们很可能会发现,客户端和服务器都收不到数据,这并不是Java标准库的设计问题,而是我们以流的形式写入数据的时候,并不是一写入就立刻发送到网络,而是先写入内存缓冲区,直到缓冲区满了以后,才会一次性真正发送到网络,这样设计的目的是为了提高传输效率。如果缓冲区的数据很少,而我们又想强制把这些数据发送到网络,就必须调用`flush()`强制把缓冲区数据发送出去。