Java IO : BIO阻塞模型

Java IO : BIO阻塞模型_第1张图片
基于BIO的多人聊天室设计与实现

Java IO : BIO阻塞模型_第2张图片
Java IO : BIO阻塞模型_第3张图片
服务端实现:

package top.onefine.demo.socket.nio.server;

import lombok.extern.slf4j.Slf4j;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;

/**
 * @author one fine
*/
@Slf4j public class ChatServer { private final int DEFAULT_PORT = 8888; private final String QUIT = "quit"; private ServerSocket serverSocket; private final Map<String, Writer> connectedClients; public ChatServer() { this.connectedClients = new HashMap<>(); } public synchronized void addClient(Socket socket) throws IOException { if (socket != null) { InetAddress address = socket.getInetAddress(); int port = socket.getPort(); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); this.connectedClients.put(address + ":" + port, writer); log.info("客户端[{}:{}]成功连接到服务器...", address, port); } } public synchronized void removeClient(Socket socket) throws IOException { if (socket != null) { InetAddress address = socket.getInetAddress(); int port = socket.getPort(); String key = address + ":" + port; if (this.connectedClients.containsKey(key)) { Writer writer = connectedClients.get(key); writer.close(); // 关闭 this.connectedClients.remove(key); log.info("客户端[{}:{}]断开与服务器连接.", address, port); } } } /** * 转发消息 * @param socket 消息发送者 * @param fwdMsg 需要转发的消息内容 */ public synchronized void forwardMessage(Socket socket, String fwdMsg) { InetAddress address = socket.getInetAddress(); int port = socket.getPort(); String key = address + ":" + port; this.connectedClients.keySet().forEach(id -> { if (!id.equals(key)) { Writer writer = connectedClients.get(id); try { writer.write(fwdMsg); writer.flush(); } catch (IOException e) { log.error("Exception: {}", e.getMessage()); } } }); } public boolean readyToQuit(String msg) { return QUIT.equalsIgnoreCase(msg); } public synchronized void close() { if (serverSocket != null) { try { serverSocket.close(); } catch (IOException e) { log.error("Exception: {}", e.getMessage()); } } } public void startServerApplication() { try { // 绑定监听窗口 serverSocket = new ServerSocket(DEFAULT_PORT); log.info("启动服务器,监听端口{} ...", DEFAULT_PORT); while (true) { // 等待客户端连接 Socket socket = serverSocket.accept(); // 创建ChatHandler线程, 处理每一个客户端的连接 Thread thread = new Thread(new ChatHandler(this, socket)); thread.setDaemon(true); thread.start(); } } catch (IOException e) { log.error("Exception: {}", e.getMessage()); } finally { this.close(); log.info("服务器已关闭."); } } public static void main(String[] args) { ChatServer server = new ChatServer(); server.startServerApplication(); } }
package top.onefine.demo.socket.nio.server;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;

/**
 * @author one fine
*/
@AllArgsConstructor @Slf4j public class ChatHandler implements Runnable { private ChatServer server; private Socket socket; @Override public void run() { try { // 存储新上线用户 server.addClient(socket); // 读取用户发送的消息 BufferedReader reader = new BufferedReader(new InputStreamReader(this.socket.getInputStream())); String msg; while ((msg = reader.readLine()) != null) { log.debug("客户端[{}:{}]发送消息: {}", socket.getInetAddress(), socket.getPort(), msg); String sendMsg = "[" + socket.getInetAddress() + ":" + socket.getPort() + "]" + msg + "\n"; // 将收到的消息转发给聊天室中在线的其他用户 server.forwardMessage(socket, sendMsg); // 退出群聊 if (this.server.readyToQuit(msg)) break; } } catch (IOException e) { log.error("Exception: {}", e.getMessage()); } finally { try { this.server.removeClient(socket); } catch (IOException e) { log.error("Exception: {}", e.getMessage()); } } } }

客户端实现:

package top.onefine.demo.socket.nio.client;

import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.net.Socket;

/**
 * @author one fine
*/
@Slf4j public class ChatClient { private final String DEFAULT_SERVER_HOST = "127.0.0.1"; private final int DEFAULT_PORT = 8888; private final String QUIT = "quit"; private Socket socket; private BufferedReader reader; private BufferedWriter writer; // 发送消息 public void send(String msg) throws IOException { if (!socket.isOutputShutdown()) { writer.write(msg + "\n"); writer.flush(); } } // 接收消息 public String receive() throws IOException { String msg = null; if (!socket.isInputShutdown()) { msg = reader.readLine(); } return msg; } // 检查用户是否需要退出群聊 public boolean readyToQuit(String msg) { return QUIT.equalsIgnoreCase(msg); } public void close() { if (writer != null) { try { writer.close(); } catch (IOException e) { log.error("Exception: {}", e.getMessage()); } } } public void startClientApplication() { try { // 创建socket socket = new Socket(DEFAULT_SERVER_HOST, DEFAULT_PORT); // 创建IO流 reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); log.info("客户端[{}:{}]连接上服务器...", socket.getLocalAddress(), socket.getLocalPort()); // 处理用户的输入 Thread thread = new Thread(new UserInputHandler(this)); thread.setDaemon(true); thread.start(); // 读取服务器转发的消息 String msg; while ((msg = receive()) != null) { log.info("收到消息: {}", msg); } } catch (IOException e) { log.error("Exception: {}", e.getMessage()); } finally { this.close(); log.info("服务器已关闭."); } } public static void main(String[] args) { ChatClient client = new ChatClient(); client.startClientApplication(); } }
package top.onefine.demo.socket.nio.client;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * @author one fine
*/
@Slf4j @AllArgsConstructor public class UserInputHandler implements Runnable { private ChatClient chatClient; @Override public void run() { try { // 等待用户输入消息 BufferedReader consoleReader = new BufferedReader(new InputStreamReader(System.in)); while (true) { String input = consoleReader.readLine(); // 向着服务器发送消息 chatClient.send(input); // 检查用户是否准备退出 if (chatClient.readyToQuit(input)) break; } } catch (IOException e) { log.error("Exception: {}", e.getMessage()); } } }

测试用户:

package top.onefine.demo.socket.nio;

import top.onefine.demo.socket.nio.client.ChatClient;

/**
 * @author one fine
*/
public class Client1 { public static void main(String[] args) { ChatClient client = new ChatClient(); client.startClientApplication(); } }
package top.onefine.demo.socket.nio;

import top.onefine.demo.socket.nio.client.ChatClient;

/**
 * @author one fine
*/
public class Client2 { public static void main(String[] args) { ChatClient client = new ChatClient(); client.startClientApplication(); } }

Java IO : BIO阻塞模型_第4张图片

代码实现(已更改部分):

package top.onefine.demo.socket.nio.server;

import lombok.extern.slf4j.Slf4j;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author one fine
*/
@Slf4j public class ChatServer { private final int DEFAULT_PORT = 8888; private final String QUIT = "quit"; private ServerSocket serverSocket; private final Map<String, Writer> connectedClients; private ExecutorService executorService; // 线程池 public ChatServer() { this.connectedClients = new HashMap<>(); this.executorService = Executors.newFixedThreadPool(10); // 固定使用十个线程 } public synchronized void addClient(Socket socket) throws IOException { if (socket != null) { InetAddress address = socket.getInetAddress(); int port = socket.getPort(); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); this.connectedClients.put(address + ":" + port, writer); log.info("客户端[{}:{}]成功连接到服务器...", address, port); } } public synchronized void removeClient(Socket socket) throws IOException { if (socket != null) { InetAddress address = socket.getInetAddress(); int port = socket.getPort(); String key = address + ":" + port; if (this.connectedClients.containsKey(key)) { Writer writer = connectedClients.get(key); writer.close(); // 关闭 this.connectedClients.remove(key); log.info("客户端[{}:{}]断开与服务器连接.", address, port); } } } /** * 转发消息 * @param socket 消息发送者 * @param fwdMsg 需要转发的消息内容 */ public synchronized void forwardMessage(Socket socket, String fwdMsg) { InetAddress address = socket.getInetAddress(); int port = socket.getPort(); String key = address + ":" + port; this.connectedClients.keySet().forEach(id -> { if (!id.equals(key)) { Writer writer = connectedClients.get(id); try { writer.write(fwdMsg); writer.flush(); } catch (IOException e) { log.error("Exception: {}", e.getMessage()); } } }); } public boolean readyToQuit(String msg) { return QUIT.equalsIgnoreCase(msg); } public synchronized void close() { if (serverSocket != null) { try { serverSocket.close(); } catch (IOException e) { log.error("Exception: {}", e.getMessage()); } } } public void startServerApplication() { try { // 绑定监听窗口 serverSocket = new ServerSocket(DEFAULT_PORT); log.info("启动服务器,监听端口{} ...", DEFAULT_PORT); while (true) { // 等待客户端连接 Socket socket = serverSocket.accept(); // 创建ChatHandler线程, 处理每一个客户端的连接 // Thread thread = new Thread(new ChatHandler(this, socket)); // thread.setDaemon(true); // thread.start(); // 使用线程池 executorService.execute(new ChatHandler(this, socket)); } } catch (IOException e) { log.error("Exception: {}", e.getMessage()); } finally { this.close(); log.info("服务器已关闭."); } } public static void main(String[] args) { ChatServer server = new ChatServer(); server.startServerApplication(); } }

你可能感兴趣的:(#,Java,socket,bio,java,io)