Java在线聊天室(客户端+服务器)

Java在线聊天室(客户端+服务器)基于webSocket实现模拟在线聊天系统

运行环境: JDK1.8version

开发环境:Eclipse

一、结构

以下是系统主要结构:

1.用户(均实现部分可能会有bug)
(1)自定义用户名登录
(2)端口修改灵活使用服务器端口
(3)断开服务器功能
(4)可查询在线用户列表
(5)可对在线列表用户进行私聊操作(自测)
(6)群发消息在线用户都可以看见消息

client代码参考如下

public class Client{
 
	private JFrame frame;
	public JList userList;
	public int i;
	public  String soloId;
	private JTextArea textArea;
	private JTextArea systemTextArea;
	private JTextField textField;
	private JTextField txt_port;
	private JTextField txt_hostIp;
	private JTextField txt_name;
//	private JComboBox select;
//	private JList jList;  
	private JButton btn_start;
	private JButton btn_stop;
	private JButton btn_send;
	private JPanel northPanel;
	private JPanel southPanel;
	private JScrollPane rightScroll;
	private JScrollPane leftScroll;
	private JSplitPane centerSplit;
 
	private DefaultListModel listModel;
	private boolean isConnected = false;
 
	private Socket socket;
	private PrintWriter writer;
	private BufferedReader reader;
	private MessageThread messageThread;// 负责接收消息的线程
	private Map<String, User> onLineUsers = new HashMap<String, User>();// 所有在线用户

	public boolean isConnected() {
		return isConnected;
	}

	public void setConnected(boolean isConnected) {
		this.isConnected = isConnected;
	}

	// 主方法,程序入口
	public static void main(String[] args) {
		new Client();
	}
 
	// 执行发送
	public void send(String c) {
		if (!isConnected) {
			JOptionPane.showMessageDialog(frame, "还没有连接服务器,无法发送消息!", "错误",
					JOptionPane.ERROR_MESSAGE);
			return;
		}
		String message = textField.getText().trim();
		if (message == null || message.equals("")) {
			JOptionPane.showMessageDialog(frame, "消息不能为空!", "错误",
					JOptionPane.ERROR_MESSAGE);
			return;
		}
		if (isConnected == false) {
			JOptionPane.showMessageDialog(frame, "您已被強制下线!", "错误",
					JOptionPane.ERROR_MESSAGE);
			return;
		}
		if(c=="all") {
			sendMessage(frame.getTitle() + "@" + "ALL" + "@" + message+"@"+ soloId);
			textField.setText(null);
				return;
		}
		if(c=="solo") {
			System.out.println(soloId+"soloId");
			sendMessage(frame.getTitle() + "@" + "SOLO" + "@" + message + "@" + soloId);
			textField.setText(null);
				return;
		}
	}
 
	// 构造方法
	public Client() {
		textArea = new JTextArea();
		systemTextArea = new JTextArea();
		textArea.setEditable(false);
		textArea.setForeground(Color.BLACK);
		systemTextArea.setEditable(false);
		systemTextArea.setForeground(Color.blue);
		
		textField = new JTextField();
		txt_port = new JTextField(8);txt_port.setText("8888");//设置大小
		txt_hostIp = new JTextField(8);txt_hostIp.setText("127.0.0.1");
		txt_name = new JTextField(8);txt_name.setText("xiaohei");
		btn_start = new JButton("连接");btn_start.setPreferredSize(new Dimension(120,10));
		btn_stop = new JButton("断开");btn_stop.setPreferredSize(new Dimension(120,10));
		btn_send = new JButton("发送");btn_send.setPreferredSize(new Dimension(120,10));
		listModel = new DefaultListModel();
		userList = new JList(listModel);
		
		
		
			
			
		
		northPanel = new JPanel(new FlowLayout(FlowLayout.LEADING,10,15));
//		northPanel.setLayout(new GridLayout(1, 7));
		Box bnorthPanel=Box.createHorizontalBox();    //创建横向Box容器
		northPanel.add(bnorthPanel);
		bnorthPanel.add(new JLabel("姓名:"));
		bnorthPanel.add(Box.createHorizontalStrut(20));
		bnorthPanel.add(txt_name);
		bnorthPanel.add(Box.createHorizontalStrut(150));
		bnorthPanel.add(new JLabel("服务器IP:"));
		bnorthPanel.add(Box.createHorizontalStrut(20));
		bnorthPanel.add(txt_hostIp);
		bnorthPanel.add(Box.createHorizontalStrut(130));
		bnorthPanel.add(new JLabel("端口:"));
		bnorthPanel.add(Box.createHorizontalStrut(20));
		bnorthPanel.add(txt_port);
		
		bnorthPanel.add(Box.createHorizontalStrut(30));
		bnorthPanel.add(btn_start);
		bnorthPanel.add(Box.createHorizontalStrut(10));
		bnorthPanel.add(btn_stop);
		northPanel.setBorder(new TitledBorder("连接信息"));
 
		rightScroll = new JScrollPane(textArea);
		textArea.add(systemTextArea);
		rightScroll.setBorder(new TitledBorder("消息显示区"));
		leftScroll = new JScrollPane(userList);
		leftScroll.setBorder(new TitledBorder("在线用户"));
		
		southPanel = new JPanel(new BorderLayout());
		southPanel.add(textField, "Center");
//		southPanel.add(select,"Center");
		southPanel.add(btn_send, "East");
		southPanel.setBorder(new TitledBorder("写消息"));
 
		centerSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftScroll,
				rightScroll);
		centerSplit.setDividerLocation(100);
 
		frame = new JFrame("客户机");
		// 更改JFrame的图标:
//		frame.setIconImage(Toolkit.getDefaultToolkit().createImage(Client.class.getResource("qq.png")));
		frame.setLayout(new BorderLayout());
		frame.add(northPanel, "North");
		frame.add(centerSplit, "Center");
		frame.add(southPanel, "South");

		frame.setSize(1050, 500);
		int screen_width = Toolkit.getDefaultToolkit().getScreenSize().width;
		int screen_height = Toolkit.getDefaultToolkit().getScreenSize().height;
		frame.setLocation((screen_width - frame.getWidth()) / 2,
				(screen_height - frame.getHeight()) / 2);
		frame.setVisible(true);
 
		// 写消息的文本框中按回车键时事件
		textField.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				send("all");
			}
		});
		//单击在线用户事件
		userList.addMouseListener(new MouseListener() {
			@Override
			public void mouseClicked(MouseEvent e) {
				// TODO Auto-generated method stub
				int i = userList.getSelectedIndex();
				soloId = (String) listModel.get(i);
				send("solo");
//				for (int i = listModel.size() - 1; i >= 0; i--) {
//					
//					System.out.println(listModel.get(i)+"111111111111");
//				}
//				new SeparateChat();
				
			}

			@Override
			public void mousePressed(MouseEvent e) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void mouseReleased(MouseEvent e) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void mouseEntered(MouseEvent e) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void mouseExited(MouseEvent e) {
				// TODO Auto-generated method stub
				
			}
				
		

			
		});
		// 单击发送按钮时事件
		btn_send.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				send("all");
			}
		});
 
		// 单击连接按钮时事件
		btn_start.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				int port;	
				if (isConnected) {
					JOptionPane.showMessageDialog(frame, "已处于连接上状态,不要重复连接!",
							"错误", JOptionPane.ERROR_MESSAGE);
					return;
				}
				try {
					try {
						port = Integer.parseInt(txt_port.getText().trim());
					} catch (NumberFormatException e2) {
						throw new Exception("端口号不符合要求!端口为整数!");
					}
					String hostIp = txt_hostIp.getText().trim();
					String name = txt_name.getText().trim();
					if (name.equals("") || hostIp.equals("")) {
						throw new Exception("姓名、服务器IP不能为空!");
					}
					
//					
				boolean flag = connectServer(port, hostIp, name);
				if (flag == false) {
					throw new Exception("与服务器连接失败!");
					
				}
					frame.setTitle(name);
					JOptionPane.showMessageDialog(frame, "成功连接!");
				} catch (Exception exc) {
					JOptionPane.showMessageDialog(frame, exc.getMessage(),
							"错误", JOptionPane.ERROR_MESSAGE);
				}
			}
		});
 
		// 单击断开按钮时事件
		btn_stop.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if (!isConnected) {
					JOptionPane.showMessageDialog(frame, "已处于断开状态,不要重复断开!",
							"错误", JOptionPane.ERROR_MESSAGE);
					return;
				}
				try {
					boolean flag = closeConnection();// 断开连接
					if (flag == false) {
						throw new Exception("断开连接发生异常!");
					}
					JOptionPane.showMessageDialog(frame, "成功断开!");
				} catch (Exception exc) {
					JOptionPane.showMessageDialog(frame, exc.getMessage(),
							"错误", JOptionPane.ERROR_MESSAGE);
				}
			}
		});
 
		// 关闭窗口时事件
		frame.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				if (isConnected) {
					closeConnection();// 关闭连接
				}
				System.exit(0);// 退出程序
			}
		});
	}
 
	/**
	 * 连接服务器
	 * 
	 * @param port
	 * @param hostIp
	 * @param name
	 */
	public boolean connectServer(int port, String hostIp, String name) {
		// 连接服务器
		try {
			socket = new Socket(hostIp, port);// 根据端口号和服务器ip建立连接
			writer = new PrintWriter(socket.getOutputStream());
			reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
	
			// 发送客户端用户基本信息(用户名和ip地址)
			sendMessage(name + "@" + socket.getLocalAddress().toString());
			
		
			// 开启接收消息的线程
			messageThread = new MessageThread(reader, textArea);
			messageThread.start();
			
			isConnected = true;// 已经连接上了
			return true;
		} catch (Exception e) {
			textArea.append("【系统消息】与端口号为:" + port + "    IP地址为:" + hostIp
					+ "   的服务器连接失败!" + "\r\n");
			isConnected = false;// 未连接上
			return false;
		}
	}
 
	/**
	 * 发送消息
	 * 
	 * @param message
	 */
	public void sendMessage(String message) {
		writer.println(message);
		writer.flush();
	}
 
	/**
	 * 客户端主动关闭连接
	 */
	@SuppressWarnings("deprecation")
	public synchronized boolean closeConnection() {
		try {
			sendMessage("CLOSE");// 发送断开连接命令给服务器
			listModel.removeAllElements();
			messageThread.stop();// 停止接受消息线程
			// 释放资源
			if (reader != null) {
				reader.close();
			}
			if (writer != null) {
				writer.close();
			}
			if (socket != null) {
				socket.close();
			}
			isConnected = false;
			return true;
		} catch (IOException e1) {
			e1.printStackTrace();
			isConnected = true;
			return false;
		}
	}
 
	// 不断接收消息的线程
	class MessageThread extends Thread {
		private BufferedReader reader;
		private JTextArea textArea;
 
		// 接收消息线程的构造方法
		public MessageThread(BufferedReader reader, JTextArea textArea) {
			this.reader = reader;
			this.textArea = textArea;
		}
 
		// 被动的关闭连接
		public synchronized void closeCon() throws Exception {
			// 清空用户列表
			listModel.removeAllElements();
			// 被动的关闭连接释放资源
			if (reader != null) {
				reader.close();
			}
			if (writer != null) {
				writer.close();
			}
			if (socket != null) {
				socket.close();
			}
			isConnected = false;// 修改状态为断开
		}
 
		public void run() {
			String message = "";
			while (true) {
				
				try {
					message = reader.readLine();
				
					StringTokenizer stringTokenizer = new StringTokenizer(
							message, "/@");
					String command = stringTokenizer.nextToken();// 命令
					System.out.println(command);
					
					
					if (command.equals("CLOSE"))// 服务器已关闭命令
					{
						textArea.append("【系统消息】服务器已关闭!\r\n");
						closeCon();// 被动的关闭连接
						return;// 结束线程
					}else if(command.equals("KickCLOSE")) {
						closeCon();// 被动的关闭连接
						return;// 结束线程
					}else if(command.equals("NAME")) {
						int size = Integer.parseInt(stringTokenizer.nextToken());
						String username = null;
						String userIp = null;
						String thisName = txt_name.getText().trim();
						for (int i = 0; i < size; i++) {
							username = stringTokenizer.nextToken();
							userIp = stringTokenizer.nextToken();
//							User user = new User(username, userIp);
						
							if(username.equals(thisName)) {
//								isConnected = false;
								sendMessage("CLOSE");// 发送断开连接命令给服务器
								closeCon();// 被动的关闭连接
								textArea.append("【系统消息】与端口号为:" + txt_port.getText().trim() + "    IP地址为:" + txt_hostIp.getText().trim()
										+ "   的服务器连接失败!" + "\r\n");
								JOptionPane.showMessageDialog(frame, "该姓名已被占用!", "错误",
										JOptionPane.ERROR_MESSAGE);
								return;
							}
						}
						
//						closeCon();// 被动的关闭连接
//						JOptionPane.showMessageDialog(frame, "该姓名已被占用!", "错误",
//								JOptionPane.ERROR_MESSAGE);
//						return;// 结束线程
					}else if (command.equals("ADD")) {// 有用户上线更新在线列表
						String username = "";
						String userIp = "";
						if ((username = stringTokenizer.nextToken()) != null
								&& (userIp = stringTokenizer.nextToken()) != null) {
							User user = new User(username, userIp);
							onLineUsers.put(username, user);
							listModel.addElement(username);
							
						}
					} else if (command.equals("DELETE")) {// 有用户下线更新在线列表
						String username = stringTokenizer.nextToken();
						User user = (User) onLineUsers.get(username);
						onLineUsers.remove(user);
						listModel.removeElement(username);
						
					} else if (command.equals("USERLIST")) {// 加载在线用户列表
						int size = Integer
								.parseInt(stringTokenizer.nextToken());
						String username = null;
						String userIp = null;
						for (int i = 0; i < size; i++) {
							username = stringTokenizer.nextToken();
							userIp = stringTokenizer.nextToken();
							User user = new User(username, userIp);
							onLineUsers.put(username, user);
							listModel.addElement(username);
						}
					
					} else if (command.equals("MAX")) {// 人数已达上限
						textArea.append(stringTokenizer.nextToken()
								+ stringTokenizer.nextToken() + "\r\n");
						closeCon();// 被动的关闭连接
						JOptionPane.showMessageDialog(frame, "服务器缓冲区已满!", "错误",
								JOptionPane.ERROR_MESSAGE);
						return;// 结束线程
					
					}
					else {// 普通消息
						textArea.append(message + "\r\n");
					}
				} catch (IOException e) {
					e.printStackTrace();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}
}

2.服务器(全部已实现)
(1)指定端口开启服务器
(2)设置服务器上线人数
(3)停止服务器响应
(4)查询在线用户列表
(5)群发消息
(6)对指定用户进行移除聊天室

server代码

public class Server {
 
	private JFrame frame;
	private JTextArea contentArea;
	private JTextField txt_message;
	private JTextField txt_max;
	private JTextField txt_port;
	private JTextField kickOutUser;
	private JButton btn_start;
	private JButton btn_stop;
	private JButton btn_send;
	private JButton btn_kick;
	private JPanel northPanel;
	private JPanel southPanel;
	private JPanel eastPanel;
	private JPanel eastUpPanel;
	private JPanel eastDownPanel;
	private JPanel westPanel;
	private JScrollPane rightPanel;
	private JScrollPane leftPanel;
	private JSplitPane centerSplit;
	private JList userList;
	private DefaultListModel listModel;
	
	private ServerSocket serverSocket;
	private ServerThread serverThread;
	private ArrayList<ClientThread> clients;
 
	private boolean isStart = false;
	private Client client;
	
//	Client client = new Client();
	// 主方法,程序执行入口
	public static void main(String[] args) {
		new Server();	
	}
 
	// 执行消息发送
	public void send() {
		if (!isStart) {
			JOptionPane.showMessageDialog(frame, "服务器还未启动,不能发送消息!", "错误",
					JOptionPane.ERROR_MESSAGE);
			return;
		}
		if (clients.size() == 0) {
			JOptionPane.showMessageDialog(frame, "没有用户在线,不能发送消息!", "错误",
					JOptionPane.ERROR_MESSAGE);
			return;
		}
		String message = txt_message.getText().trim();
		if (message == null || message.equals("")) {
			JOptionPane.showMessageDialog(frame, "消息不能为空!", "错误",
					JOptionPane.ERROR_MESSAGE);
			return;
		}
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
		String Time = df.format(new Date());
		
		sendServerMessage(message);// 群发服务器消息
		contentArea.append(Time + "  " + "服务器说:" + txt_message.getText() + "\r\n");
		txt_message.setText(null);
	}
	
	// 构造放法
	public Server() {
//		client = new Client();
		frame = new JFrame("服务器");
		// 更改JFrame的图标:
		//frame.setIconImage(Toolkit.getDefaultToolkit().createImage(Client.class.getResource("qq.png")));
//		frame.setIconImage(Toolkit.getDefaultToolkit().createImage(Server.class.getResource("/KeTang/WebContent/img/bg.jpg")));
		contentArea = new JTextArea();
		contentArea.setEditable(false);
		contentArea.setForeground(Color.black);
		txt_message = new JTextField();
		txt_max = new JTextField(8);txt_max.setText("6");
		txt_port = new JTextField(8);txt_port.setText("8888");
		kickOutUser = new JTextField(8);kickOutUser.setText("xiaohei");
		btn_start = new JButton("启动");btn_start.setPreferredSize(new Dimension(120,10));
		btn_stop = new JButton("停止");btn_stop.setPreferredSize(new Dimension(120,10));
		btn_send = new JButton("发送");btn_send.setPreferredSize(new Dimension(120,10));
		btn_kick = new JButton("踢");
		btn_stop.setEnabled(false);
		listModel = new DefaultListModel();
		userList = new JList(listModel);
 
		southPanel = new JPanel(new BorderLayout());
		southPanel.setBorder(new TitledBorder("写消息"));
		southPanel.add(txt_message, "Center");
		southPanel.add(btn_send, "East");
		
		leftPanel = new JScrollPane(userList);
		leftPanel.setBorder(new TitledBorder("在线用户"));
		rightPanel = new JScrollPane(contentArea);
		rightPanel.setBorder(new TitledBorder("消息显示区"));

		centerSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel,
				rightPanel);
		centerSplit.setDividerLocation(100);
		
		northPanel = new JPanel(new FlowLayout(FlowLayout.LEADING,10,15));
//		northPanel.setLayout(new GridLayout(1, 6));
		Box bnorthPanel=Box.createHorizontalBox();    //创建横向Box容器
		northPanel.add(bnorthPanel);
		bnorthPanel.add(new JLabel("人数上限:"));
		bnorthPanel.add(Box.createHorizontalStrut(20));
		bnorthPanel.add(txt_max);
		bnorthPanel.add(Box.createHorizontalStrut(150));
		bnorthPanel.add(new JLabel("端口:"));
		bnorthPanel.add(Box.createHorizontalStrut(20));
		bnorthPanel.add(txt_port);
		bnorthPanel.add(Box.createHorizontalStrut(30));
		bnorthPanel.add(btn_start);
		bnorthPanel.add(Box.createHorizontalStrut(10));
		bnorthPanel.add(btn_stop);
		northPanel.setBorder(new TitledBorder("配置信息"));
		
		eastUpPanel = new JPanel(new FlowLayout(FlowLayout.LEADING,3,15));
		eastUpPanel.add(new JLabel("被踢用户:"));
		eastUpPanel.add(kickOutUser);
		eastUpPanel.add(btn_kick);
		
		eastDownPanel = new JPanel();
		Box beastDownPanel=Box.createVerticalBox();    //创建纵向Box容器
		eastDownPanel.add(beastDownPanel);
		beastDownPanel.add(Box.createVerticalStrut(150));
		beastDownPanel.add(new JLabel("未完待续..."));
		
		eastPanel = new JPanel(new BorderLayout());
		eastPanel.add(eastUpPanel,"North");
		eastPanel.add(eastDownPanel,"Center");
		eastPanel.setBorder(new TitledBorder("服务器功能操作"));
		
		westPanel = new JPanel(new BorderLayout());
		westPanel.add(northPanel,"North");
		westPanel.add(centerSplit, "Center");
		westPanel.add(southPanel, "South");
		
		frame.setLayout(new BorderLayout());

		frame.add(westPanel, "West");
		frame.add(eastPanel, "East");
		frame.setSize(1050, 500);
		//frame.setSize(Toolkit.getDefaultToolkit().getScreenSize());//设置全屏
		int screen_width = Toolkit.getDefaultToolkit().getScreenSize().width;
		int screen_height = Toolkit.getDefaultToolkit().getScreenSize().height;
		frame.setLocation((screen_width - frame.getWidth()) / 2,
				(screen_height - frame.getHeight()) / 2);
		frame.setVisible(true);
 
		// 关闭窗口时事件
		frame.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				if (isStart) {
					closeServer();// 关闭服务器
				}
				System.exit(0);// 退出程序
			}
		});
		//单击踢出用户
		btn_kick.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				String a = kickOutUser.getText().trim();
				kickOutUser(a);
			}

		});
 
		// 文本框按回车键时事件
		txt_message.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				send();
			}
		});
 
		// 单击发送按钮时事件
		btn_send.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				send();
			}
		});
 
		// 单击启动服务器按钮时事件
		btn_start.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if (isStart) {
					JOptionPane.showMessageDialog(frame, "服务器已处于启动状态,不要重复启动!",
							"错误", JOptionPane.ERROR_MESSAGE);
					return;
				}
				int max;
				int port;
				try {
					try {
						max = Integer.parseInt(txt_max.getText());
					} catch (Exception e1) {
						throw new Exception("人数上限为正整数!");
					}
					if (max <= 0) {
						throw new Exception("人数上限为正整数!");
					}
					try {
						port = Integer.parseInt(txt_port.getText());
					} catch (Exception e1) {
						throw new Exception("端口号为正整数!");
					}
					if (port <= 0) {
						throw new Exception("端口号 为正整数!");
					}
					serverStart(max, port);
					contentArea.append("服务器已成功启动!人数上限:" + max + ",端口:" + port
							+ "\r\n");
					JOptionPane.showMessageDialog(frame, "服务器成功启动!");
					btn_start.setEnabled(false);
					txt_max.setEnabled(false);
					txt_port.setEnabled(false);
					btn_stop.setEnabled(true);
				} catch (Exception exc) {
					JOptionPane.showMessageDialog(frame, exc.getMessage(),
							"错误", JOptionPane.ERROR_MESSAGE);
				}
			}
		});
		// 单击停止服务器按钮时事件
		btn_stop.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if (!isStart) {
					JOptionPane.showMessageDialog(frame, "服务器还未启动,无需停止!", "错误",
							JOptionPane.ERROR_MESSAGE);
					return;
				}
				try {
					closeServer();
					btn_start.setEnabled(true);
					txt_max.setEnabled(true);
					txt_port.setEnabled(true);
					btn_stop.setEnabled(false);
					contentArea.append("服务器成功停止!\r\n");
					JOptionPane.showMessageDialog(frame, "服务器成功停止!");
				} catch (Exception exc) {
					JOptionPane.showMessageDialog(frame, "停止服务器发生异常!", "错误",
							JOptionPane.ERROR_MESSAGE);
				}
			}
		});
	}
	// 踢出用户方法	
	public void kickOutUser(String kickOutUser){
		
			User user = new User(kickOutUser, kickOutUser);
			boolean exist = false;
			SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
			String Time = df.format(new Date());
			//当前是否有启动服务器
			if (!isStart) {
				JOptionPane.showMessageDialog(frame, "服务器还未启动,不能踢出!", "错误",
						JOptionPane.ERROR_MESSAGE);
				return;
			}
			//当前是否有用户
			if (clients.size() == 0) {
				JOptionPane.showMessageDialog(frame, "没有用户在线,踢出失败!", "错误",
						JOptionPane.ERROR_MESSAGE);
				return;
			}
				
			for (int i = clients.size() - 1; i >= 0; i--) {
				ClientThread temp = clients.get(i);
				if (clients.get(i).getUser().getName().equals(kickOutUser)) {
					//服务器窗口显示该用户强制下线消息
					contentArea.append(Time+"  "+clients.get(i).getUser().getName()
							+ clients.get(i).getUser().getIp() + "被强制下线!\r\n");
					//给该用户发送强制下线消息
					clients.get(i).getWriter().println(
							"【系统消息】用户"+clients.get(i).getUser().getName()+"您已被强制下线!\r\n");
					clients.get(i).getWriter().flush();
					// 更新在线列表
					listModel.removeElement(clients.get(i).getUser().getName());
						
					clients.get(i).getWriter().println("KickCLOSE");
					clients.get(i).getWriter().flush();
					
					clients.remove(i);// 删除此用户的服务线程
					temp.stop();// 停止这条服务线程
					exist = true;
	//						client.setConnected(false);
				}
			}
			
			if (exist == false) {
				JOptionPane.showMessageDialog(frame, "该用户不在线,踢出失败!", "错误",
						JOptionPane.ERROR_MESSAGE);
			}
			
			for (int i = clients.size() - 1; i >= 0; i--) {
				// 向所有在线用户发送该用户的下线命令
				clients.get(i).getWriter().println(
						"DELETE@" + user.getName());
				clients.get(i).getWriter().println(
						"【系统消息】用户"+user.getName()+"被强制下线!\r\n");
				clients.get(i).getWriter().flush();
				
			}
		
			
	}
	
	
	

	// 启动服务器
	public void serverStart(int max, int port) throws java.net.BindException {
		try {
			clients = new ArrayList<ClientThread>();
			serverSocket = new ServerSocket(port);
			serverThread = new ServerThread(serverSocket, max);
			serverThread.start();
			isStart = true;
		} catch (BindException e) {
			isStart = false;
			throw new BindException("端口号已被占用,请换一个!");
		} catch (Exception e1) {
			e1.printStackTrace();
			isStart = false;
			throw new BindException("启动服务器异常!");
		}
	}
 
	// 关闭服务器
	@SuppressWarnings("deprecation")
	public void closeServer() {
		try {
			if (serverThread != null)
				serverThread.stop();// 停止服务器线程
 
			for (int i = clients.size() - 1; i >= 0; i--) {
				// 给所有在线用户发送关闭命令
				clients.get(i).getWriter().println("CLOSE");
				clients.get(i).getWriter().flush();
				// 释放资源
				clients.get(i).stop();// 停止此条为客户端服务的线程
				clients.get(i).reader.close();
				clients.get(i).writer.close();
				clients.get(i).socket.close();
				clients.remove(i);
			}
			if (serverSocket != null) {
				serverSocket.close();// 关闭服务器端连接
			}
			listModel.removeAllElements();// 清空用户列表
			isStart = false;
		} catch (IOException e) {
			e.printStackTrace();
			isStart = true;
		}
	}
 
	// 群发服务器消息
	public void sendServerMessage(String message) {
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
		String Time = df.format(new Date());
		for (int i = clients.size() - 1; i >= 0; i--) {
			clients.get(i).getWriter().println("【系统消息】"+"服务器:" + message);
			clients.get(i).getWriter().flush();
		}
	}
 
	// 服务器线程
	class ServerThread extends Thread {
		private ServerSocket serverSocket;
		private int max;// 人数上限
 
		// 服务器线程的构造方法
		public ServerThread(ServerSocket serverSocket, int max) {
			this.serverSocket = serverSocket;
			this.max = max;
		}
 
		public synchronized void run() {
			SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
			String Time = df.format(new Date());
			while (true) {// 不停的等待客户端的链接
				try {
					Socket socket = serverSocket.accept();
					if (clients.size() == max) {// 如果已达人数上限
						BufferedReader r = new BufferedReader(
								new InputStreamReader(socket.getInputStream()));
						PrintWriter w = new PrintWriter(socket.getOutputStream());
						// 接收客户端的基本用户信息
						String inf = r.readLine();
						StringTokenizer st = new StringTokenizer(inf, "@");
						User user = new User(st.nextToken(), st.nextToken());
						// 反馈连接成功信息
						w.println("MAX@【系统消息】服务器:对不起," + user.getName()
								+ user.getIp() + ",服务器在线人数已达上限,请稍后尝试连接!");
						w.flush();
						// 释放资源
						r.close();
						w.close();
						socket.close();
						continue;
					}
					
					
					ClientThread client = new ClientThread(socket);
					client.start();// 开启对此客户端服务的线程
					clients.add(client);
					listModel.addElement(client.getUser().getName());// 更新在线列表
					
					contentArea.append(Time+"  "+client.getUser().getName()
							+ client.getUser().getIp() + "上线了!\r\n");
					
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
 
	// 为一个客户端服务的线程
	class ClientThread extends Thread {
		private Socket socket;
		private BufferedReader reader;
		private PrintWriter writer;
		private User user;
 
		public BufferedReader getReader() {
			return reader;
		}
 
		public PrintWriter getWriter() {
			return writer;
		}
 
		public User getUser() {
			return user;
		}
		
		// 客户端线程的构造方法
		public ClientThread(Socket socket) {
			try {
				this.socket = socket;
				reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
				writer = new PrintWriter(socket.getOutputStream());
				// 接收客户端的基本用户信息
				String inf = reader.readLine();
				StringTokenizer st = new StringTokenizer(inf, "@");
				user = new User(st.nextToken(), st.nextToken());
				String temp = "";
				
				SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
				String Time = df.format(new Date());
				
				// 反馈连接成功信息
				writer.println("【系统消息】" + user.getName() + user.getIp() + "与服务器连接成功!");
				writer.flush();
				
				// 反馈当前在线用户信息
				if (clients.size() > 0) {
					for (int i = clients.size() - 1; i >= 0; i--) {
						temp += (clients.get(i).getUser().getName() + "/" + clients
								.get(i).getUser().getIp())
								+ "@";
						if(clients.get(i).getUser().getName().equals(user.getName())) {
							writer.println("NAME@" + clients.size() + "@" + temp);//判断姓名是否重复
							writer.flush();
						}
					}
					
					
					writer.println("USERLIST@" + clients.size() + "@" + temp);
					writer.flush();
				}
				
				
				
				// 向所有在线用户发送该用户上线命令
				for (int i = clients.size() - 1; i >= 0; i--) {
					clients.get(i).getWriter().println(
							"ADD@" + user.getName() + user.getIp());
//					clients.get(i).getWriter().flush();
//					clients.get(i).getWriter().println(
//							"【系统消息】用户"+user.getName()+"上线了!\r\n");
					clients.get(i).getWriter().flush();
				}
				for (int i = clients.size() - 1; i >= 0; i--) {
					clients.get(i).getWriter().println(
							"【系统消息】用户"+user.getName()+"上线了!\r\n");
					clients.get(i).getWriter().flush();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
 
		@SuppressWarnings("deprecation")
		public void run() {// 不断接收客户端的消息,进行处理。
			String message = null;
			SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
			String Time = df.format(new Date());
			while (true) {
				try {
					message = reader.readLine();// 接收客户端消息
				
					if (message.equals("CLOSE"))// 下线命令
					{
						contentArea.append(Time+"  "+this.getUser().getName()
								+ this.getUser().getIp() + "下线了!\r\n");
						// 断开连接释放资源
						reader.close();
						writer.close();
						socket.close();
 
						// 向所有在线用户发送该用户的下线命令
						for (int i = clients.size() - 1; i >= 0; i--) {
							clients.get(i).getWriter().println(
									"DELETE@" + user.getName());
							clients.get(i).getWriter().flush();
						}
						for (int i = clients.size() - 1; i >= 0; i--) {
							clients.get(i).getWriter().println(
									"【系统消息】用户"+user.getName()+"下线了!\r\n");
							clients.get(i).getWriter().flush();
						}
 
						listModel.removeElement(user.getName());// 更新在线列表
 
						// 删除此条客户端服务线程
						for (int i = clients.size() - 1; i >= 0; i--) {
							if (clients.get(i).getUser() == user) {
								ClientThread temp = clients.get(i);
								clients.remove(i);// 删除此用户的服务线程
								temp.stop();// 停止这条服务线程
								return;
							}
						}
					}
					else {
						dispatcherMessage(message);// 多人转发消息

					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			
		}
		
		
		// 转发消息
		public void dispatcherMessage(String message) {
			StringTokenizer stringTokenizer = new StringTokenizer(message, "@");
			String source = stringTokenizer.nextToken();
			String owner = stringTokenizer.nextToken();
			String content = stringTokenizer.nextToken();
			String soloId = stringTokenizer.nextToken();
			
			SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
			String Time = df.format(new Date());
			
			if (owner.equals("ALL")) {// 群发
				message =Time + "  " + source + ":" + content;
				contentArea.append(message + "\r\n");
				for (int i = clients.size() - 1; i >= 0; i--) {
					clients.get(i).getWriter().println(message);
					clients.get(i).getWriter().flush();
				}
			} else if (owner.equals("SOLO")) {
				message =Time + "  " + source + "对" + soloId+ ":" + content;
				contentArea.append(message + "\r\n");
				for (int i = clients.size() - 1; i >= 0; i--) {
					if (clients.get(i).getUser().getName().equals(user.getName())) {//当前用户一对一发送
						message =Time + "  " + "你对" + soloId + ":" + content;
						clients.get(i).getWriter().println(message);
						clients.get(i).getWriter().flush();
					}
					if (clients.get(i).getUser().getName().equals(soloId)) {//一对一发送给soloId
						message =Time + "  " +source + "对你:" + content;
						clients.get(i).getWriter().println(message);
						clients.get(i).getWriter().flush();
					}
				}
			}
			
			
		}
//		public void dispatcherSoloMessage(String message) {
//			StringTokenizer stringTokenizer = new StringTokenizer(message, "@");
//			String source = stringTokenizer.nextToken();
//			String owner = stringTokenizer.nextToken();
//			String content = stringTokenizer.nextToken();
//			String soloId = stringTokenizer.nextToken();
//			message = source + ":" + content;
//			contentArea.append(message + "\r\n");
//			
				String soloString = client.soloId;
				System.out.println("2222222222");
				System.out.println(soloString+"11111111111");
				for (int i = clients.size() - 1; i >= 0; i--) {
					if(clients.get(i).getName().equals(soloString)) {
					clients.get(i).getWriter().println(message + "(单独发送)");
					clients.get(i).getWriter().flush();
			}
//		
//		}
	}
}

代码仅供参考~
附上运行截图:
Java在线聊天室(客户端+服务器)_第1张图片
Java在线聊天室(客户端+服务器)_第2张图片

获取项目:点击这里

你可能感兴趣的:(Java,java)