java-基于swing的多线程聊天室

这个多线程聊天室是用swing的WindowBuilder做的页面,已经测试过了,可能有点小瑕疵,可留言指出

package test9;

/**
 * 用户信息
 * @author Administrator
 *
 */
public class User {
	private String name;
	private String ip;
	
	public User() {
		super();
		// TODO Auto-generated constructor stub
	}
	public User(String name, String ip) {
		super();
		this.name = name;
		this.ip = ip;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getIp() {
		return ip;
	}
	public void setIp(String ip) {
		this.ip = ip;
	}
	
}
<pre name="code" class="java">package test9;

import java.awt.BorderLayout;

public class Server extends JFrame {

	private JPanel contentPane;
	private JTextField textPort;
	private JTextField textSend;
	private boolean isStart = false;
	private List<ClientThread> client = null;
	private JTextArea textShow;
	private ServerSocket serverSocket;
	private ServerThread serverThread;
	private JButton btnStop, btnStart;

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					Server frame = new Server();
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the frame.
	 */
	public Server() {
		setTitle("服务器");
		setResizable(false);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 400, 500);
		setLocationRelativeTo(null);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		contentPane.setLayout(new BorderLayout(0, 0));
		setContentPane(contentPane);

		JPanel panel = new JPanel();
		panel.setBorder(new TitledBorder(null, "\u914D\u7F6E\u4FE1\u606F",
				TitledBorder.LEADING, TitledBorder.TOP, null, null));
		contentPane.add(panel, BorderLayout.NORTH);

		JLabel lblNewLabel = new JLabel("端口号:");
		panel.add(lblNewLabel);

		textPort = new JTextField();
		panel.add(textPort);
		textPort.setColumns(10);

		btnStart = new JButton("启动");
		btnStart.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				start();
			}
		});
		panel.add(btnStart);

		btnStop = new JButton("停止");
		btnStop.setEnabled(false);
		btnStop.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				stop();
			}
		});
		panel.add(btnStop);

		JScrollPane scrollPane = new JScrollPane();
		contentPane.add(scrollPane, BorderLayout.CENTER);

		textShow = new JTextArea();
		textShow.setEditable(false);
		scrollPane.setViewportView(textShow);

		JPanel panel_1 = new JPanel();
		contentPane.add(panel_1, BorderLayout.SOUTH);

		textSend = new JTextField();
		textSend.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				send();
			}
		});
		textSend.setColumns(25);
		panel_1.add(textSend);

		JButton btnSend = new JButton("发送");
		btnSend.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				send();
			}
		});
		panel_1.add(btnSend);
	}

	/**
	 * 发送消息
	 */
	public void send() {
		if (!isStart) {
			JOptionPane.showMessageDialog(this, "服务器还未启动,请先启动服务器");
			return;
		}
		if (client.size() == 0) {
			JOptionPane.showMessageDialog(this, "没有用户在线,不能发送消息!");
			return;
		}
		String message = textSend.getText().trim(); // 去掉字符串头部和尾部的空字符串
		if (message == null || message.equals("")) {
			JOptionPane.showMessageDialog(this, "消息不能为空!");
			return;
		}
		sendServerMessage(message); // 群发消息
		textShow.append("服务器说:" + textSend.getText() + "\r\n");
		textSend.setText(null);
	}

	/**
	 * 群发消息
	 * 
	 * @param message
	 */
	public void sendServerMessage(String message) {
		for (int i = client.size() - 1; i >= 0; i--) {
			client.get(i).getWrite().println("服务器:" + message);
			client.get(i).getWrite().flush();
		}
	}

	/**
	 * 单击启动按钮事件
	 * 
	 * @param port
	 * @return
	 */
	public void start() {
		if (isStart) {
			JOptionPane.showMessageDialog(this, "服务器已经启动过啦!");
			return;
		}
		int port = -1;
		try {
			port = Integer.parseInt(textPort.getText());
			if (port < 0) {
				JOptionPane.showMessageDialog(this, "端口号为正整数!");
				return;
			}
			serverStart(port);
			textShow.append("服务器已启动!端口号:" + port + "\r\n");
			JOptionPane.showMessageDialog(this, "服务器启动成功!");
			btnStart.setEnabled(false); // 开始按钮锁定
			textPort.setEditable(false); // 端口号文本框锁定
			btnStop.setEnabled(true); // 停止按钮解除锁定
		} catch (Exception e) {
			JOptionPane.showMessageDialog(this, "端口号为正整数!");
		}
	}

	/**
	 * 单击停止按钮事件
	 */
	public void stop() {
		if (!isStart) {
			JOptionPane.showMessageDialog(this, "服务器还未启动,无需停止!");
			return;
		}
		try {
			closeServer();
			btnStart.setEnabled(true);
			textPort.setEditable(true);
			btnStop.setEnabled(false);
			textShow.append("服务器已成功停止!\r\n");
			JOptionPane.showMessageDialog(this, "服务器已停止!");
		} catch (Exception e) {
			// TODO: handle exception
			JOptionPane.showMessageDialog(this, "停止服务器发生异常!");
		}
	}

	/**
	 * 启动服务器
	 */
	public void serverStart(int port) {
		client = new ArrayList<ClientThread>();
		try {
			serverSocket = new ServerSocket(port);
			serverThread = new ServerThread(serverSocket);
			serverThread.start();
			isStart = true;
		} catch (BindException e) {
			isStart = false;
			JOptionPane.showMessageDialog(this, "端口号被占用!");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			isStart = false;
			JOptionPane.showMessageDialog(this, "服务器启动异常");
		}
	}

	/**
	 * 关闭服务器
	 */
	public void closeServer() {
		try {
			if (serverThread != null) {
				serverThread.stop(); // 停止服务线程
			}

			// 发布给所有在线用户下线的消息
			for (int i = client.size() - 1; i >= 0; i--) {
				client.get(i).getWrite().println("CLOSE");
				client.get(i).getWrite().flush();
				// 释放资源
				client.get(i).stop(); // 停止此条为客户服务的线程
				client.get(i).read.close();
				client.get(i).write.close();
				client.get(i).socket.close();
				client.remove(i);
			}
			// 关闭服务器连接
			if (serverSocket != null) {
				serverSocket.close();
			}
			isStart = false;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			isStart = true;
		}
	}

	/**
	 * 服务器线程
	 * 
	 * @author Administrator
	 *
	 */
	class ServerThread extends Thread {
		private ServerSocket serverSocket;

		public ServerThread(ServerSocket serverSocket) {
			this.serverSocket = serverSocket;
		}

		@Override
		public void run() {
			// 不停地等待客户连接
			while (true) {
				try {
					Socket socket = serverSocket.accept();
					ClientThread clients = new ClientThread(socket);
					clients.start(); // 开启客户端服务线程
					client.add(clients);
					textShow.append(clients.getUser().getName()
							+ clients.getUser().getIp() + "上线了!\r\n");
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}

	}

	/**
	 * 为每个客户端服务的线程
	 * 
	 * @author Administrator
	 *
	 */
	class ClientThread extends Thread {
		private Socket socket;
		private BufferedReader read;
		private PrintWriter write;
		private User user;

		public BufferedReader getRead() {
			return read;
		}

		public PrintWriter getWrite() {
			return write;
		}

		public User getUser() {
			return user;
		}

		public ClientThread(Socket socket) {
			super();
			this.socket = socket;
			try {
				read = new BufferedReader(new InputStreamReader(
						socket.getInputStream()));
				write = new PrintWriter(socket.getOutputStream());
				// 接受用户信息
				String info = read.readLine();
				StringTokenizer st = new StringTokenizer(info, "@");
				user = new User(st.nextToken(), st.nextToken());
				// 反馈连接成功的信息
				write.print(user.getName() + user.getIp() + "与服务器连接成功!\r\n");
				write.flush();
				// 反馈当前所有在线用户信息
				if (client.size() > 0) {
					String temp = "";
					for (int i = client.size() - 1; i >= 0; i--) {
						temp += (client.get(i).getUser().getName() + "/" + client
								.get(i).getUser().getIp())
								+ "@";
					}
					write.print("USERLIST@" + client.size() + "@" + temp);
					write.flush();
				}

				// 向所有的用户发送该用户上线的消息
				for (int i = client.size() - 1; i >= 0; i--) {
					client.get(i).getWrite()
							.println("ADD@" + user.getName() + user.getIp());
					client.get(i).getWrite().flush();
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		/**
		 * 不断接受客户传来的消息,进行处理
		 */
		@Override
		public void run() {
			String message = null;
			while (true) {
				try {
					message = read.readLine(); // 接受消息
					if (message.equals("CLOSE")) { // 下线命令
						textShow.append(this.getUser().getName()
								+ this.getUser().getIp() + "下线!\r\n");
						// 断开连接的资源
						read.close();
						write.close();
						socket.close();

						// 向所有在线用户发送该用户下线的消息
						for (int i = client.size() - 1; i >= 0; i--) {
							client.get(i)
									.getWrite()
									.println(
											"DELETE@"
													+ client.get(i).getUser()
															.getName());
							client.get(i).getWrite().flush();
						}

						// 删除此条客户端的服务线程
						for (int i = client.size() - 1; i >= 0; i--) {
							if (client.get(i).getUser() == user) {
								ClientThread temp = client.get(i);
								client.remove(i); // 删除此用户的服务线程
								temp.stop(); // 停止该条线程
								return;
							}
						}
					} else {
						dispatcherMessage(message);
					}

				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 * 转发消息
	 * 
	 * @param message
	 */
	public void dispatcherMessage(String message) {
		StringTokenizer st = new StringTokenizer(message, "@");
		String source = st.nextToken();
		String owner = st.nextToken();
		String contant = st.nextToken();
		message = source + "说:" + contant;
		textShow.append(message + "\r\n");
		if (owner.equals("ALL")) { // 群发
			for (int i = client.size() - 1; i >= 0; i--) {
				client.get(i).getWrite().println(message);
				client.get(i).getWrite().flush();
			}
		}
	}

}


 
<pre name="code" class="java">package test9;

import java.awt.BorderLayout;

public class Client extends JFrame {

	private JPanel contentPane;
	private JTextField textIp;
	private JTextField textPort;
	private JTextField textName;
	private JTextField textSend;
	private boolean isCon = false;
	private BufferedReader read;
	private PrintWriter write;
	private Socket socket;
	private JTextArea textShow;
	private JButton btnCon;
	private JButton btnCurrent;
	
	private Map<String, User> onLineUser = new HashMap<String, User>(); // 所有在线的用户
	private MessageThread messageThread;

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					Client frame = new Client();
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the frame.
	 */
	public Client() {
		setResizable(false);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 594, 500);
		setLocationRelativeTo(null);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		setContentPane(contentPane);
		contentPane.setLayout(new BorderLayout(0, 0));

		JPanel panel = new JPanel();
		panel.setBorder(new TitledBorder(null, "\u914D\u7F6E\u4FE1\u606F",
				TitledBorder.LEADING, TitledBorder.TOP, null, null));
		contentPane.add(panel, BorderLayout.NORTH);

		JLabel lblIp = new JLabel("IP地址:");
		panel.add(lblIp);

		textIp = new JTextField();
		panel.add(textIp);
		textIp.setColumns(7);

		JLabel label = new JLabel("端口号:");
		panel.add(label);

		textPort = new JTextField();
		panel.add(textPort);
		textPort.setColumns(5);

		JLabel label_1 = new JLabel("姓名:");
		panel.add(label_1);

		textName = new JTextField();
		panel.add(textName);
		textName.setColumns(5);

		btnCon = new JButton("连接");
		btnCon.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				con();
			}
		});
		panel.add(btnCon);

		btnCurrent = new JButton("断开");
		btnCurrent.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				current();
			}
		});
		btnCurrent.setEnabled(false);
		panel.add(btnCurrent);

		JScrollPane scrollPane = new JScrollPane();
		contentPane.add(scrollPane, BorderLayout.CENTER);

		textShow = new JTextArea();
		textShow.setEditable(false);
		scrollPane.setViewportView(textShow);

		JPanel panel_1 = new JPanel();
		contentPane.add(panel_1, BorderLayout.SOUTH);

		textSend = new JTextField();
		textSend.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				send();
			}
		});
		panel_1.add(textSend);
		textSend.setColumns(40);

		JButton btnSend = new JButton("发送");
		btnSend.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				send();
			}
		});
		panel_1.add(btnSend);
	}
	
	/**
	 * 发送消息
	 */
	public void send(){
		if(!isCon){
			JOptionPane.showMessageDialog(this, "还没有连接服务器,无法发送消息!");
			return;
		}
		String message = textSend.getText().trim();
		if(message == null || message.equals("")){
			JOptionPane.showMessageDialog(this, "消息不能为空");
			return;
		}
		sendMessage(this.getTitle() + "@" + "ALL" + "@" + message);
		textSend.setText(null);
	}

	/**
	 * 点击连接按钮事件处理
	 */
	public void con() {
		int port = -1;
		if(isCon){
			JOptionPane.showMessageDialog(this, "已经处于连接状态,不能重复连接!");
			return;
		}
		try {
			try {
				port = Integer.parseInt(textPort.getText().trim());
			} catch (Exception e) {
				JOptionPane.showMessageDialog(this, "输入的端口号不规范,要求为整数!");
			}
			String hostIp = textIp.getText().trim();
			String name = textName.getText().trim();
			if(hostIp.equals("") || name.equals("")){
				JOptionPane.showMessageDialog(this, "Ip地址和用户名都不能为空!");
				return;
			}
			boolean flag = connecServer(port, hostIp, name);
			if(flag == false){
				JOptionPane.showMessageDialog(this, "与服务器连接失败!");
				return;
			}
			this.setTitle(name);
			JOptionPane.showMessageDialog(this, "成功连接!");
			
			textPort.setEditable(false);
			textIp.setEditable(false);
			textName.setEditable(false);
			btnCon.setEnabled(false);
			btnCurrent.setEnabled(true);
			
		} catch (Exception e) {
			JOptionPane.showMessageDialog(this, e.toString());
		}
	}
	
	/**
	 * 断开事件处理
	 */
	public void current(){
		if(!isCon){
			JOptionPane.showMessageDialog(this, "已经是断开状态了哦!");
			return;
		}
		try {
			boolean flag = closeCon();		//断开连接
			if(!flag){
				JOptionPane.showMessageDialog(this, "断开连接发生异常!");
				return;
			}
			JOptionPane.showConfirmDialog(this,"断开成功!");
			
			textPort.setEditable(true);
			textIp.setEditable(true);
			textName.setEditable(true);
			btnCon.setEnabled(true);
			btnCurrent.setEnabled(false);
			
		} catch (Exception e) {
			// TODO: handle exception
			JOptionPane.showMessageDialog(this, e.toString());
		}
			
	}

	/**
	 * 连接服务器
	 * @param port
	 * @param hostIp
	 * @param name
	 * @return
	 */
	public boolean connecServer(int port, String hostIp, String name) {
		try {
			socket = new Socket(hostIp, port); // 根据端口号号和服务器
			write = new PrintWriter(socket.getOutputStream());
			read = new BufferedReader(new InputStreamReader(
					socket.getInputStream()));
			//发送客户端的基本信息
			sendMessage(name+"@"+socket.getLocalAddress().toString());
			//开启接收消息的线程
			messageThread = new MessageThread(read, textShow);
			messageThread.start();
			isCon = true;		//状态改为:已连接
			return true;
		} catch (Exception e) {
			// TODO: handle exception
			textShow.append("与端口号为:"+port+",Ip地址为:"+hostIp+"的服务器连接失败!\r\n");
			isCon = false;		//状态为:未连接
			return false;
		}
	}

	/**
	 * 客户端主动关闭连接
	 * 
	 * @return
	 */
	public synchronized boolean closeCon() {
		try {
			sendMessage("CLOSE"); // 发送断开连接命令给服务器
			messageThread.stop(); // 停止接受消息的线程
			// 释放资源
			if (read != null) {
				read.close();
			}
			if (write != null) {
				write.close();
			}
			if (socket != null) {
				socket.close();
			}
			isCon = false;
			return true;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			isCon = true;
			return false;
		}

	}

	/**
	 * 发送消息
	 * 
	 * @param message
	 */
	public void sendMessage(String message) {
		write.println(message);
		write.flush();
	}

	/**
	 * 不断接受消息的线程
	 * @author Administrator
	 *
	 */
	class MessageThread extends Thread {
		private BufferedReader read;
		private JTextArea textShow;

		// 接收消息线程的构造方法
		public MessageThread(BufferedReader read, JTextArea textShow) {
			super();
			this.read = read;
			this.textShow = textShow;
		}

		// 被动关闭连接
		public synchronized void closeCon() throws Exception {
			// 被动关闭连接释放资源
			if (read != null) {
				read.close();
			}
			if (write != null) {
				write.close();
			}
			if (socket != null) {
				socket.close();
			}
			isCon = false; // 将状态改为未连接状态
			textPort.setEditable(true);
			textIp.setEditable(true);
			textName.setEditable(true);
			btnCon.setEnabled(true);
			btnCurrent.setEnabled(false);
		}

		@Override
		public void run() { // 不断接受消息
			String message = "";
			while (true) {
				try {
					message = read.readLine();
					StringTokenizer st = new StringTokenizer(message, "/@");
					String command = st.nextToken(); // 命令
					if (command.equals("CLOSE")) { // 关闭命令
						textShow.append("服务器已关闭!\r\n");
						closeCon(); // 被动关闭连接
						return; // 结束线程
					} else if (command.equals("ADD")) { // 有用户上线更新列表
						String userName = "";
						String userIp = "";
						if ((userName = st.nextToken()) != null
								&& (userIp = st.nextToken()) != null) {
							User user = new User(userName, userIp);
							onLineUser.put(userName, user);
						}
					} else if (command.equals("DELETE")) { // 有用户下线更新列表
						String userName = st.nextToken();
						User user = (User) onLineUser.get(userName);
						onLineUser.remove(userName);
					} else if (command.equals("USERLIST")) {
						int size = Integer.parseInt(st.nextToken());
						String userName = null;
						String userIp = null;
						for (int i = 0; i < size; i++) {
							userName = st.nextToken();
							userIp = st.nextToken();
							User user = new User(userName, userIp);
							onLineUser.put(userName, user);
						}
					} else { // 普通消息
						textShow.append(message + "\r\n");
					}

				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}

}


 

显示效果:



  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值