Java 聊天室

Java:多人聊天室(Socket+Runnable+ThreadPool+I/O)

需求:

  1. 一个服务器、多个客户端,客户端之间要有明显的代号加以区分。
  2. 当有新的客户端连接服务器,服务器应该分配给新的代号,并且在服务器控制台刷新连接信息。
  3. 当客户端 A 发送消息,除了客户端 A 外,其他客户端同时收到这条消息。
  4. 当有客户端断开连接,在服务器控制台刷新连接信息。
  5. 客户端有两种断开连接方式:
    a:手动强制关闭客户端 A 的线程,服务器应将客户端 A 已断开连接通知给其他客户端 。
    b:客户端 A 输入断开连接语句正常退出,服务器应通知客户端 A 已正常断开连接,并将此消息通知其他客户端。
  6. 若服务器在还有客户端连接的情况下线程中断,应该告知所有客户端连接断开。

分割线----------------------------------------------------------------------------------------------------------------分割线

代码:

Server:服务器类

import java.io.*;
import java.net.*;
import java.util.*;
import java.util.concurrent.*;

/*
 * 服务器端程序
 */
public class Server {

	// 客户端的昵称
	private static Character name = 64;

	// 客户端的输出流与昵称的Map关系
	private Map<PrintWriter, Character> map = null;

	// 服务器Socket
	private ServerSocket serverSocket = null;

	// 线程池
	private ExecutorService pool = null;

	// 构造方法,用于初始化
	public Server() {

		super();

		try {
			serverSocket = new ServerSocket(8888);
			map = new HashMap<PrintWriter, Character>();
			pool = Executors.newFixedThreadPool(10);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	// 服务端开启方法
	public void start() {

		Socket socket = null;

		try {

			// 监听客户端
			while (true) {
				
				System.out.println("等待客户端连接……");
				socket = serverSocket.accept();// accept()是阻塞方法
				System.out.println("客户端已连接!");
				
				// 启动一个线程去处理该客户端的请求
				ClientHandler clientHandler = new ClientHandler(socket);
				pool.execute(clientHandler);
				name++;
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {

			Util.shut(null, null, null, null, null, socket);

			if (serverSocket != null) {

				try {
					serverSocket.close();
				} catch (IOException e) {
					System.out.println("ServerSocket已关闭");
				}
			}
		}
	}

	// 内部类
	// 线程类,用户处理客户端请求
	private class ClientHandler implements Runnable {

		private Socket socket = null;

		public ClientHandler(Socket socket) {
			super();
			this.socket = socket;
		}

		@Override
		public void run() {

			InputStream inputStream = null;
			InputStreamReader inputStreamReader = null;
			BufferedReader bufferReader = null;

			OutputStream outputStream = null;
			OutputStreamWriter outputStreamWriter = null;
			PrintWriter printWriter = null;

			try {

				// 获取客户端消息
				inputStream = socket.getInputStream();
				inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
				bufferReader = new BufferedReader(inputStreamReader);

				// 获取客户端输出流
				outputStream = socket.getOutputStream();
				outputStreamWriter = new OutputStreamWriter(outputStream, "UTF-8");
				printWriter = new PrintWriter(outputStreamWriter, true);

				// 将客户端的输出流保存到Map中
				addMap(printWriter, name);

				System.out.println("当前连接的客户端数:" + map.size());
				sendMap(socket);

				boolean isOk = true;
				String message = bufferReader.readLine();
				while (isOk) {

					// 判断客户端是否选择退出
					if ("exit".equalsIgnoreCase(message) || message == null) {

						isOk = false;

						String notice = "客户端" + map.get(printWriter) + "/" + socket.getInetAddress() + "与服务器断开连接!";
						System.out.println(notice);
						sendList(printWriter, notice);

						// 从Map中移除此客户端
						removeMap(printWriter);

						System.out.println("当前连接的客户端数:" + map.size());
						sendMap(socket);

					} else {

						// 遍历所有输出流
						do {
							message = map.get(printWriter).toString() + "/" + socket.getInetAddress() + ":" + message;
							sendList(printWriter, message);
						} while ((message = bufferReader.readLine()) != null);
					}
				}
			} catch (SocketException e) {

				System.out.println("客户端" + map.get(printWriter) + "/" + socket.getInetAddress() + "与服务器断开连接!");

				// 从Map中移除此线程
				removeMap(printWriter);
				System.out.println("当前连接的客户端数:" + map.size());

				sendMap(socket);
			}

			catch (IOException e) {
				e.printStackTrace();
			} finally {

				// 从Map中移除此客户端
				removeMap(printWriter);

				// 关闭资源
				Util.shut(bufferReader, inputStreamReader, outputStreamWriter, inputStream, outputStream, socket);
			}
		}

		// 添加同步方法
		private synchronized void addMap(PrintWriter printWriter, Character name) {
			map.put(printWriter, name);
		}

		// 移除同步方法
		private synchronized void removeMap(PrintWriter printWriter) {
			map.remove(printWriter);
		}

		// 打印同步方法
		private synchronized void sendMap(Socket socket) {

			Set<PrintWriter> set = map.keySet();

			if (map.size() != 0) {// 当Map中还有元素,则打印元素内容
				for (PrintWriter printWriter : set) {
					System.out.println(map.get(printWriter) + "/" + socket.getInetAddress());
				}
			}
		}

		// 输出同步方法
		private synchronized void sendList(PrintWriter printWriter, String message) {

			Set<PrintWriter> set = map.keySet();

			for (PrintWriter pw : set) {
				if (pw != printWriter) {
					pw.println(message);
				}
			}
		}
	}

	public static void main(String[] args) {

		Server server = new Server();
		server.start();
	}
}

Client:客户端类

import java.io.*;
import java.net.*;
import java.util.*;

/*
 * 客户端程序
 */
public class Client {

	// 客户端Socket
	private Socket socket;

	// 构造方法,用于初始化
	public Client() {

		super();

		try {
			socket = new Socket("localhost", 8888);
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	// 客户端工作方法
	public void start() {

		OutputStream outputStream = null;
		OutputStreamWriter outputStreamWriter = null;
		PrintWriter printWriter = null;

		Scanner scanner = null;

		try {

			// 启动接收服务器信息的线程
			ServerHandler serverHandler = new ServerHandler(socket);
			Thread thread = new Thread(serverHandler);
			thread.setDaemon(true);// 设置为守护线程
			thread.start();

			outputStream = socket.getOutputStream();
			outputStreamWriter = new OutputStreamWriter(outputStream, "UTF-8");
			printWriter = new PrintWriter(outputStreamWriter, true);

			// 读取用户输入的内容
			scanner = new Scanner(System.in);

			while (true) {

				String string = scanner.nextLine();
				printWriter.println(string);

				// 如果用户输入exit,则退出循环
				if ("exit".equalsIgnoreCase(string)) {
					System.out.println("您已成功断开与服务器的连接");
					break;
				}
			}
		} catch (ConnectException e) {
			System.out.println("服务器未启动,请先启动服务器");
		} catch (SocketException e) {
			System.out.println("与服务器失去联系");
		} catch (IOException e) {
			System.out.println("发生IO异常");
		} finally {

			Util.shut(null, null, outputStreamWriter, null, outputStream, socket);
			if (scanner != null) {
				scanner.close();
			}
		}
	}

	private class ServerHandler implements Runnable {

		private Socket socket;

		public ServerHandler(Socket socket) {
			super();
			this.socket = socket;
		}

		@Override
		public void run() {

			InputStream inputStream = null;
			InputStreamReader inputStreamReader = null;
			BufferedReader bufferReader = null;

			try {

				inputStream = socket.getInputStream();
				inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
				bufferReader = new BufferedReader(inputStreamReader);

				while (true) {
					System.out.println(bufferReader.readLine());
				}
			} catch (SocketException e) {
				System.out.println("与服务器断开连接");
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				Util.shut(bufferReader, inputStreamReader, null, inputStream, null, socket);
			}
		}
	}

	public static void main(String[] args) {

		Client client = new Client();
		client.start();
	}
}

Util:工具类

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

class Util {

	static void shut(BufferedReader bufferReader, InputStreamReader inputStreamReader,OutputStreamWriter outputStreamWriter, InputStream inputStream, OutputStream outputStream, Socket socket) {

		if (bufferReader != null) {
			try {
				bufferReader.close();
			} catch (IOException e) {
				System.out.println("BufferReader已关闭");
			}
		}

		if (inputStreamReader != null) {
			try {
				inputStreamReader.close();
			} catch (IOException e) {
				System.out.println("InputStreamReader已关闭");
			}
		}

		if (outputStreamWriter != null) {
			try {
				outputStreamWriter.close();
			} catch (IOException e) {
				System.out.println("OutputStreamWriter已关闭");
			}
		}

		if (inputStream != null) {
			try {
				inputStream.close();
			} catch (IOException e) {
				System.out.println("InputStream已关闭");
			}
		}

		if (outputStream != null) {
			try {
				outputStream.close();
			} catch (IOException e) {
				System.out.println("OutputStream已关闭");
			}
		}

		if (socket != null) {
			try {
				socket.close();
			} catch (IOException e) {
				System.out.println("Socket已关闭");
			}
		}
	}
}

你可能感兴趣的:(Java)