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();
}
}
}