tcp 服务器端;
即 在 TCPServer 中 有一个 客户端监听类ClientListener ,
使用 do-while() 不停的监听 客户端的连接,即 监听到一个客户端的到来,就创建一个
ClientHandler客户端处理类(在这个类中 有两个 线程类:ClientReadHandler 和ClientWriteHandler )
这样就实现了 数据发送与接收 并行。
1.首先在 TCPServer 的start 函数中 先 启动 ClientListener【客户端监听类】:
2. ClientListener 类:
在其run() 函数中 使用 do while() 不停的监听客户端,
client = server.accept(); 是阻塞 函数
直到 有客户端连接才继续执行,
当有 客户端连接 时,就创建异步线程(将客户端消息的读取和发送由别的线程完成):
##################################################################
private class ClientListener extends Thread {
private ServerSocket server;
private boolean done = false;
private ClientListener(int port) throws IOException {
server = new ServerSocket(port);
System.out.println("服务器信息:" + server.getInetAddress() + " P:" + server.getLocalPort());
}
@Override
public void run() {
super.run();
System.out.println("服务器准备就绪~");
// 等待客户端连接
do {
// 得到客户端
Socket client;
try {
client = server.accept();
} catch (IOException e) {
continue;
}
try {
// 客户端构建异步线程
ClientHandler clientHandler = new ClientHandler(client,
handler -> clientHandlerList.remove(handler));
// 读取数据并打印
clientHandler.readToPrint();
clientHandlerList.add(clientHandler);
} catch (IOException e) {
e.printStackTrace();
System.out.println("客户端连接异常:" + e.getMessage());
}
} while (!done);
System.out.println("服务器已关闭!");
}
void exit() {
done = true;
try {
server.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
##################################################################
3. ClientHandler 类:
在这个类中,将消息的读取 和 发送 分成了两个线程:
private final ClientReadHandler readHandler;
private final ClientWriteHandler writeHandler;
##################################################################
package server.handle; import clink.net.qiujuer.clink.utils.CloseUtils; import java.io.*; import java.net.Socket; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ClientHandler { private final Socket socket; private final ClientReadHandler readHandler; private final ClientWriteHandler writeHandler; private final CloseNotify closeNotify; public ClientHandler(Socket socket, CloseNotify closeNotify) throws IOException { this.socket = socket; this.readHandler = new ClientReadHandler(socket.getInputStream()); this.writeHandler = new ClientWriteHandler(socket.getOutputStream()); this.closeNotify = closeNotify; System.out.println("新客户端连接:" + socket.getInetAddress() + " P:" + socket.getPort()); } public void exit() { readHandler.exit(); writeHandler.exit(); CloseUtils.close(socket); System.out.println("客户端已退出:" + socket.getInetAddress() + " P:" + socket.getPort()); } public void send(String str) { writeHandler.send(str); } public void readToPrint() { readHandler.start(); } private void exitBySelf() { exit(); closeNotify.onSelfClosed(this); } public interface CloseNotify { void onSelfClosed(ClientHandler handler); } class ClientReadHandler extends Thread { private boolean done = false; private final InputStream inputStream; ClientReadHandler(InputStream inputStream) { this.inputStream = inputStream; } @Override public void run() { super.run(); try { // 得到输入流,用于接收数据 BufferedReader socketInput = new BufferedReader(new InputStreamReader(inputStream)); do { // 客户端拿到一条数据 String str = socketInput.readLine(); if (str == null) { System.out.println("客户端已无法读取数据!"); // 退出当前客户端 ClientHandler.this.exitBySelf(); break; } // 打印到屏幕 System.out.println(str); } while (!done); } catch (Exception e) { if (!done) { System.out.println("连接异常断开"); ClientHandler.this.exitBySelf(); } } finally { // 连接关闭 CloseUtils.close(inputStream); } } void exit() { done = true; CloseUtils.close(inputStream); } } class ClientWriteHandler { private boolean done = false; private final PrintStream printStream; private final ExecutorService executorService; ClientWriteHandler(OutputStream outputStream) { this.printStream = new PrintStream(outputStream); this.executorService = Executors.newSingleThreadExecutor(); } void exit() { done = true; CloseUtils.close(printStream); executorService.shutdownNow(); } void send(String str) { executorService.execute(new WriteRunnable(str)); } class WriteRunnable implements Runnable { private final String msg; WriteRunnable(String msg) { this.msg = msg; } @Override public void run() { if (ClientWriteHandler.this.done) { return; } try { ClientWriteHandler.this.printStream.println(msg); } catch (Exception e) { e.printStackTrace(); } } } } }
##################################################################