聊天室

Server

package server;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

import util.CharacterUtil;
import util.XMLUtil;

public class Server extends JFrame{
	private static final long serialVersionUID = 702914498470132647L;

	private JLabel jLabel1;

	private JLabel jLabel2;

	private JLabel jLabel3;

	private JButton jButton;

	private JPanel jPanel1;

	private JPanel jPanel2;

	private JScrollPane jScrollPane;

	private JTextArea jTextArea;

	private JTextField jTextField;
	
	private Map<String, ServerMessageThread> map = new HashMap();
	
	public Server(String name)
	{
		super(name);

		this.initComponents(); //initialize UI
	}
	public Map<String, ServerMessageThread> getMap()
	{
		return map;
	}

	public JLabel getJLabel2()
	{
		return jLabel2;
	}

	public JButton getJButton()
	{
		return jButton;
	}

	public JTextArea getJTextArea()
	{
		return jTextArea;
	}

	public JTextField getJTextField()
	{
		return jTextField;
	}

	public void setJTextField(JTextField textField)
	{
		jTextField = textField;
	}
	
	private void initComponents()
	{
		jPanel1 = new JPanel();
		jPanel2 = new JPanel();
		
		jLabel1 = new JLabel();
		jLabel2 = new JLabel();
		jLabel3 = new JLabel();
		
		jTextField = new JTextField(10);
		jButton = new JButton();
		jScrollPane = new JScrollPane();
		jTextArea = new JTextArea();
		

		jPanel1.setBorder(BorderFactory.createTitledBorder("服务器信息"));
		jPanel2.setBorder(BorderFactory.createTitledBorder("在线用户列表"));

		jTextField.setText("5000");
		
		jLabel1.setText("服务器状态");
		jLabel2.setText("停止");
		jLabel2.setForeground(new Color(204, 0, 51));
		jLabel3.setText("端口号");

		jButton.setText("启动服务器");
		
		
		jButton.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				Server.this.execute(e);
			}
		});
		this.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e){
				try
				{
					Collection<ServerMessageThread> cols = Server.this.map.values();
					
					String messageXML = XMLUtil.constructCloseServerWindowXML();
					
					for(ServerMessageThread smt : cols)
					{
						smt.sendMessage(messageXML);
					}
				}
				catch(Exception ex)
				{
					ex.printStackTrace();
				}
				finally
				{
					System.exit(0);
				}
			}
		});

		jPanel1.add(jLabel1);
		jPanel1.add(jLabel2);
		jPanel1.add(jLabel3);
		jPanel1.add(jTextField);
		jPanel1.add(jButton);

		jTextArea.setEditable(false); //不允许用户手动修改在线用户列表
		jTextArea.setRows(20);
		jTextArea.setColumns(30);
		jTextArea.setForeground(new Color(0, 51, 204));

		jScrollPane.setViewportView(jTextArea); //将JTextArea放置到JScrollPane中

		jPanel2.add(jScrollPane);

		this.getContentPane().add(jPanel1, BorderLayout.NORTH);
		this.getContentPane().add(jPanel2, BorderLayout.SOUTH);

		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setAlwaysOnTop(true);
		this.setResizable(false);
		this.pack();
		this.setVisible(true);
	}

	/**
	 * 处理点击button时的事件处理
	 * @param evt
	 */
	private void execute(ActionEvent evt)
	{
		String hostPort=this.getJTextField().getText();
		
		//进行输入的判断
		if(CharacterUtil.isEmpty(hostPort))
		{
			JOptionPane.showMessageDialog(this, "端口号不能为空","提示",JOptionPane.WARNING_MESSAGE);
			return;
		}
		int port = Integer.parseInt(hostPort);
		
		new ServerConnection(this, port).start();
	}

	public static void main(String[] args)
	{
		new Server("服务器");
	}
	
}

ServerMessageThread

package server;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Collection;
import java.util.Map;
import java.util.Set;

import util.CharacterUtil;
import util.XMLUtil;

public class ServerMessageThread extends Thread{
	private Server server;
	
	private InputStream is;
	
	private OutputStream os;
	
	public ServerMessageThread(Server server, Socket socket)
	{
		try
		{
			this.server = server;
			
			this.is = socket.getInputStream();
			
			this.os = socket.getOutputStream();
		}
		catch(Exception ex)
		{
			ex.printStackTrace();
		}
	}
	// 更新用户列表
	// 首先更新服务器端的用户列表
	// 然后更新客户端的用户列表
	public void updateUserList(){
		//获得用户名的集合
		Set<String> users = this.server.getMap().keySet();
		//构造向客户端发送的在线用户列表数据xml
		String xml = XMLUtil.constructUserList(users);
		
		String str = "";
		
		for(String user : users){
			str += user + "\n";
		}
		
		//首先更新服务器端的用户列表
		this.server.getJTextArea().setText(str);
		
		Collection<ServerMessageThread> cols = this.server.getMap().values();
		
		//遍历与每一个客户端对应的线程,向每一个客户端发送在线用户列表
		for(ServerMessageThread smt : cols){
			smt.sendMessage(xml);
		}
	}

	//向客户端发送数据
	public void sendMessage(String message)
	{
		try
		{
			os.write(message.getBytes());
		}
		catch(Exception ex)
		{
			ex.printStackTrace();
		}
	}
	
	@Override
	public void run()
	{
		while(true)
		{
			try
			{
				byte[] buf = new byte[5000];
				
				int length = this.is.read(buf);
				
				//客户端发来的消息
				String xml = new String(buf,0,length);
				
				int type = Integer.parseInt(XMLUtil.extractType(xml));
				
				// 聊天数据
				if(CharacterUtil.CLIENT_MESSAGE == type)
				{
					//用户名(谁发来的消息)
					String username = XMLUtil.extractUsername(xml);
					//聊天的文本内容
					String content = XMLUtil.extractContent(xml);
					
					//构造向所有客户端发送的消息
					String message = username + " : " + content;
					//向所有客户端发送的XML聊天数据
					String messageXML = XMLUtil.constructServerMessageXML(message);
					
					Map<String, ServerMessageThread> map = this.server.getMap();
					
					Collection<ServerMessageThread> cols = map.values();
					
					for(ServerMessageThread smt : cols)
					{
						//向XML聊天数据发送给每一个客户端
						smt.sendMessage(messageXML);
					}
				}
				// 关闭客户端窗口
				else if(CharacterUtil.CLOSE_CLIENT_WINDOW == type)
				{
					String username = XMLUtil.extractUsername(xml);
					//获得待删除用户所对应的线程对象
					ServerMessageThread smt = this.server.getMap().get(username);
					//构造出向客户端确认关闭的XML信息
					String confirmationXML = XMLUtil.constructCloseClientWindowConfirmationXML();
					//向客户端发送任意一条确认信息
					smt.sendMessage(confirmationXML);
					
					// 从用户列表的Map中将该用户去除
					this.server.getMap().remove(username);
					// 更新在线用户列表
					this.updateUserList();
					
					this.is.close();
					this.os.close();
					
					break; // 结束该线程
				}				
			}
			catch(Exception ex)
			{
				
			}
		}
	}

}

ServerConnection

package server;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

import javax.swing.JOptionPane;

import util.XMLUtil;

public class ServerConnection extends Thread{
	private ServerSocket serverSocket;
	
	private Server server;
	
	public ServerConnection(Server server, int port)
	{
		try
		{
			this.server = server;
			
			this.serverSocket = new ServerSocket(port);
			
		}
		catch(Exception ex)
		{
			ex.printStackTrace();
			
			JOptionPane.showMessageDialog(this.server, "端口号被占用!", "警告", JOptionPane.ERROR_MESSAGE);
		}
		
		finally
		{
			this.server.getJLabel2().setText("运行");
			this.server.getJButton().setEnabled(false);
		}
	}
	
	@Override
	public void run()
	{
		while(true)
		{
			try
			{
				Socket socket = this.serverSocket.accept();
				
				InputStream is = socket.getInputStream();
				OutputStream os = socket.getOutputStream();
				
				byte[] buf = new byte[5000];
				int length = is.read(buf);
				
				//客户端发来的连接信息(包括了用户名)
				String loginXML = new String(buf, 0, length); 
				
				// 从客户端登录数据中提取出用户名信息(username)
				String username = XMLUtil.extractUsername(loginXML);
				
				String loginResult = null;
				
				// 判断用户是否登录成功
				boolean isLogin = false;
				
				// 判断用户名是否重复
				// 用户名重复
				if(this.server.getMap().containsKey(username))
				{
					loginResult = "failure";
				}
				// 用户名不重复
				else
				{
					loginResult = "success";
					
					isLogin = true;
				}
				
				String xml = XMLUtil.constructLoginResultXML(loginResult);
				
				os.write(xml.getBytes());
				
				// 如果用户登录成功,启动线程
				if(isLogin)
				{
					// 准备创建新的线程,用于处理用户的聊天数据,每一个连接上的用户都会对应一个该线程
					ServerMessageThread serverMessageThread = new ServerMessageThread(this.server, socket);
					//将用户名及与之对应的线程对象 放到Map中
					this.server.getMap().put(username, serverMessageThread);
					
					//更新用户列表(服务器端+客户端)
					serverMessageThread.updateUserList();
					
					serverMessageThread.start();
				}				
			}
			catch(Exception ex)
			{
				ex.printStackTrace();
			}
		}
	}

}

Client

package client;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class Client extends JFrame {
	private JButton jButton1;
	private JButton jButton2;
	
	private JLabel jLabel1;
	private JLabel jLabel2;
	private JLabel jLabel3;
	
	private JPanel jPanel;
	
	private JTextField username;
	private JTextField hostAddress;
	private JTextField port;
	
	public Client(String name) {
		super(name);
		this.initComponents();
	}
	
	private void initComponents() {
		jPanel = new JPanel();
		
		jLabel1 = new JLabel();
		jLabel2 = new JLabel();
		jLabel3 = new JLabel();
		
		username = new JTextField(15);
		hostAddress = new JTextField(15);
		port = new JTextField(15);
		
		jButton1 = new JButton();
		jButton2 = new JButton();
		
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setAlwaysOnTop(true);
		this.setResizable(false);
		
		jPanel.setBorder(BorderFactory.createTitledBorder("用户登录"));
		
		jLabel1.setText("用户名");
		jLabel2.setText("服务器");
		jLabel3.setText("端口号");
		
		jButton1.setText("登录");
		jButton2.setText("重置");
		
		jButton1.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				Client.this.login(e);
			}
		});
		
		username.setText("张三");
		hostAddress.setText("localhost");
		port.setText("5000");
		
		jPanel.add(jLabel1);
		jPanel.add(username);
		jPanel.add(jLabel2);
		jPanel.add(hostAddress);
		jPanel.add(jLabel3);
		jPanel.add(port);

		jPanel.add(jButton1);
		jPanel.add(jButton2);
		
		this.getContentPane().add(jPanel);

		this.setSize(250, 300);
		this.setVisible(true);
		
	}
	
	private void login(ActionEvent event)
	{
		String username = this.username.getText();
		String hostAddress = this.hostAddress.getText();
		String port = this.port.getText();
		
		ClientConnection clientConnection = new ClientConnection(this, hostAddress, Integer.parseInt(port), username);
		
		if(clientConnection.login())
		{
			clientConnection.start();
		}
		else
		{
			JOptionPane.showMessageDialog(this, "用户名重复!", "错误", JOptionPane.ERROR_MESSAGE);
		}
	}
	public static void main(String[] args)
	{
		new Client("用户登录"); 
	}
	
}

ChatClient

package client;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

public class ChatClient extends JFrame{
	private static final long serialVersionUID = 3452901554774086218L;
	private JButton jButton1;
	private JButton jButton2;
	private JPanel jPanel1;
	private JPanel jPanel2;
	private JPanel jPanel3;
	private JScrollPane jScrollPane1;
	private JScrollPane jScrollPane2;
	private JTextArea jTextArea1;
	private JTextArea jTextArea2;
	private JTextField jTextField;
	
	private ClientConnection clientConnection;
	public ChatClient(ClientConnection clientConnection)
	{
		this.clientConnection = clientConnection;
		
		initComponents();
	}
	
	public JTextArea getJTextArea2(){
		return jTextArea2;
	}

	public JTextArea getJTextArea1(){
		return jTextArea1;
	}
	
	private void initComponents() {
		jPanel1 = new JPanel();
		jScrollPane1 = new JScrollPane();
		jTextArea1 = new JTextArea();
		jTextField = new JTextField(20);
		jButton1 = new JButton();
		jButton2 = new JButton();
		jPanel2 = new JPanel();
		jScrollPane2 = new JScrollPane();
		jTextArea2 = new JTextArea();

		jPanel3 = new JPanel();
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setTitle("聊天室");
		jPanel1.setBorder(BorderFactory.createTitledBorder("聊天室信息"));
		jPanel2.setBorder(BorderFactory.createTitledBorder("在线用户列表"));
		jTextArea1.setColumns(30);
		jTextArea1.setRows(25);

		jTextArea2.setColumns(20);
		jTextArea2.setRows(25);
		
		this.jTextArea1.setEditable(false);
		this.jTextArea2.setEditable(false);
		
		jPanel3.add(jTextField);
		jPanel3.add(jButton1);
		jPanel3.add(jButton2);
		
		jPanel1.setLayout(new BorderLayout());
		jPanel1.add(jScrollPane1, BorderLayout.NORTH);
		jPanel1.add(jPanel3, BorderLayout.SOUTH);

		jPanel2.add(jScrollPane2);
		
		jScrollPane1.setViewportView(jTextArea1);
		jScrollPane2.setViewportView(jTextArea2);

		jButton1.setText("发送");
		jButton2.setText("清屏");
		
		jButton1.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				ChatClient.this.sendMessage(e);
			}
		});
		
		this.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e){
				try
				{
					ChatClient.this.clientConnection.sendMessage("client closed", "5");
				}
				catch(Exception ex)
				{
					ex.printStackTrace();
				}
			}
		});
		
		this.setLayout(new FlowLayout());
		this.getContentPane().add(jPanel1);
		this.getContentPane().add(jPanel2);

		this.pack();
		this.setVisible(true);
	}
	
	private void sendMessage(ActionEvent event){
		// 用户聊天的数据
		String message = this.jTextField.getText();
		// 清空聊天数据
		this.jTextField.setText("");
		// 向服务器端发送聊天数据
		this.clientConnection.sendMessage(message, "2");
	}
}

ClientConnection

package client;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.List;

import javax.swing.JOptionPane;

import util.CharacterUtil;
import util.XMLUtil;

public class ClientConnection extends Thread{
	private String hostAddress;
	
	private int port;
	
	private String username;
	
	private Client client;
	
	private Socket socket;
	
	private InputStream is;
	
	private OutputStream os;
	
	private ChatClient chatClient;
	
	public ClientConnection(Client client, String hostAddress, int port, String username) {
		this.client = client;
		this.hostAddress = hostAddress;
		this.port = port;
		this.username = username;
		//连接服务器
		this.connect2Server();	
	}
	private void connect2Server() {
		try {
			this.socket = new Socket(this.hostAddress, this.port);
			this.is = this.socket.getInputStream();
			this.os = this.socket.getOutputStream();
		}catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		
	}
	public boolean login() {
		try {
			String xml = XMLUtil.constructLoginXML(this.username);
			os.write(xml.getBytes());// 向服务器端发送用户的登录信息(其中包含了用户名)
			byte[] buf = new byte[5000];
			int length = is.read(buf);
			String loginResultXML = new String(buf, 0, length);
			String loginResult = XMLUtil.extractLoginResult(loginResultXML);
			// 登录成功
			if("success".equals(loginResult)){
				//打开聊天室主窗口
				this.chatClient = new ChatClient(this);
				this.client.setVisible(false);
				return true;
			}
			// 登录失败
			else{
				return false;
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} // 向服务器端发送用户的登录信息(其中包含了用户名)
		return false;
	}
	public Socket getSocket()
	{
		return socket;
	}
	public void sendMessage(String message, String type) {
		int t = Integer.parseInt(type);
		String xml = null;
		//客户端向服务器端发送聊天数据
		if(CharacterUtil.CLIENT_MESSAGE == t)
		{
			xml = XMLUtil.constructMessageXML(this.username, message);
		}
		//客户端向服务器端发送关闭窗口的数据
		else if(CharacterUtil.CLOSE_CLIENT_WINDOW == t)
		{
			xml = XMLUtil.constructCloseClientWindowXML(this.username);
		}
		
		//向服务器端发送数据
		try {
			this.os.write(xml.getBytes());
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	@Override
	public void run() {
		try {
			while(true) {
				byte[] buf = new byte[5000];
				int length = is.read(buf);
				
				String xml = new String(buf, 0, length);
				System.out.println(xml);
				
				int type = Integer.parseInt(XMLUtil.extractType(xml));
//				System.out.println(type+","+CharacterUtil.USER_LIST);
				
				//在线用户列表
				if(type == CharacterUtil.USER_LIST)
				{
					List<String> list = XMLUtil.extractUserList(xml);
					
					String users = "";
					
					for(String user : list)
					{
						users += user + "\n";
					}
					System.out.println("hahahahaha"+list+",,,"+xml);
					
					this.chatClient.getJTextArea2().setText(users);
				}
				// 服务器端发来的聊天数据
				else if(type == CharacterUtil.SERVER_MESSAGE)
				{
					String content = XMLUtil.extractContent(xml);
					
					this.chatClient.getJTextArea1().append(content + "\n");
				}
				// 关闭服务器端窗口
				else if(type == CharacterUtil.CLOSE_SERVER_WINDOW)
				{
					JOptionPane.showMessageDialog(this.chatClient, "服务器端已关闭,程序将退出!",
							"信息", JOptionPane.INFORMATION_MESSAGE);
					
					System.exit(0); //客户端退出
				}
				// 服务器端确认关闭客户端窗口
				else if(type == CharacterUtil.CLOSE_CLIENT_WINDOW_CONFIRMATION)
				{
					try
					{
						this.getSocket().getInputStream().close();
						this.getSocket().getOutputStream().close();
						this.getSocket().close();
					}
					catch(Exception ex)
					{
						
					}
					finally
					{
						System.exit(0);//退出客户端程序
					}
				}
			}
		}catch (Exception ex) {
			// TODO: handle exception
			ex.printStackTrace();
		}
	}

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凉寒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值