Java聊天室

1.首先是服务器的界面实现,如下:

2.如何实现呢?主要使用swing和awt,首先整个是一个Frame容器,然后设定它的布局为BoderLayout,最上边的是一个Panel,设定它的布局为GridLayout,中间使用了JSplitPane,把左右两个面板放在里面

 最下边也是一个面板,里面套了写组件

package com.example.li;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.BindException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.StringTokenizer;
 
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.border.TitledBorder;

public class Server {
	private JFrame frame;
	private JTextArea contentArea;
    private JTextField txt_message;
    private JTextField txt_max;
    private JTextField txt_port;
    private JButton btn_start;
    private JButton btn_stop;
    private JButton btn_send;
    private JPanel northPanel;
    private JPanel southPanel;
    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;
    
    public static void main(String []args)
    {
    	new Server();
    }
    
    public Server() {
    	frame = new JFrame("服务器");
    	//放在bin下包中文件
    	frame.setIconImage(Toolkit.getDefaultToolkit().createImage(Server.class.getResource("qq.jpg")));
        contentArea = new JTextArea();
        contentArea.setEditable(false);
        contentArea.setForeground(Color.pink);
    	txt_message = new JTextField();
    	txt_max = new JTextField("30");
    	txt_port = new JTextField("6666");
    	btn_start = new JButton("启动");
    	btn_stop = new JButton("停止");
    	btn_send = new JButton("发送");
    	btn_stop.setEnabled(false);
    	//使用了defaultListModel可以是列表的可选项是动态改变的!如果不用,列表中只能出现代码中定义的那些可选项
    	listModel = new DefaultListModel();
    	
    	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);
        northPanel = new JPanel();
        northPanel.setLayout(new GridLayout(1,6));
        northPanel.add(new JLabel("人数上限"));
        northPanel.add(txt_max);
        northPanel.add(new JLabel("端口"));
        northPanel.add(txt_port);
        northPanel.add(btn_start);
        northPanel.add(btn_stop);
        northPanel.setBorder(new TitledBorder("配置信息"));
        frame.setLayout(new BorderLayout());
        frame.add(northPanel,"North");
        frame.add(centerSplit,"Center");
        frame.add(southPanel, "South");
    	frame.setSize(600, 400); 
    	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);
    }
}

界面已经实现,下面改实现服务器应有的功能,服务器功能需求分析:

1.接发信息(群发)

2.开启和关闭服务器

3.在线用户显示(实时修改)

具体步骤分析:

首先需要先开启服务器才能发送信息,启动服务器时,检查相关配置信息是否正确,如端口号

    服务开启后,创建一个服务器线程来管理,并监听相关端口,若服务器线程监听到客户端请求(客户端会发出一些关于自己的用户信息,给服务器处理),则创建一个客户端线程来处理请求,客户端线程则处理来自客户端的信息,向所有在线用户反馈信息,并发送其上线通知,同时加入到 用户列表中

   服务器关闭后,需要释放所有客户端线程资源和缓冲流资源

  群发消息,则通过已有的所有客户端线程列表,向所有在线用户发送信息

package com.example.li;
 
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.BindException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.StringTokenizer;
 
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.border.TitledBorder;
 
public class Server {  
       
    private JFrame frame;  
    private JTextArea contentArea;  
    private JTextField txt_message;  
    private JTextField txt_max;  
    private JTextField txt_port;  
    private JButton btn_start;  
    private JButton btn_stop;  
    private JButton btn_send;  
    private JPanel northPanel;  
    private JPanel southPanel;  
    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;  
   
    // 主方法,程序执行入口  
    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;  
        }  
        sendServerMessage(message);// 群发服务器消息  
        contentArea.append("服务器说:" + txt_message.getText() + "\r\n");  
        txt_message.setText(null);  
    }  
   
    // 构造放法  
    public Server() {  
        frame = new JFrame("服务器");  
        // 更改JFrame的图标:  
        //frame.setIconImage(Toolkit.getDefaultToolkit().createImage(Client.class.getResource("qq.png")));  
        frame.setIconImage(Toolkit.getDefaultToolkit().createImage(Server.class.getResource("qq.jpg")));  
        contentArea = new JTextArea();  
        contentArea.setEditable(false);  
        contentArea.setForeground(Color.blue);  
        txt_message = new JTextField();  
        txt_max = new JTextField("30");  
        txt_port = new JTextField("6666");  
        btn_start = new JButton("启动");  
        btn_stop = new JButton("停止");  
        btn_send = 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();  
        northPanel.setLayout(new GridLayout(1, 6));  
        northPanel.add(new JLabel("人数上限"));  
        northPanel.add(txt_max);  
        northPanel.add(new JLabel("端口"));  
        northPanel.add(txt_port);  
        northPanel.add(btn_start);  
        northPanel.add(btn_stop);  
        northPanel.setBorder(new TitledBorder("配置信息"));  
   
        frame.setLayout(new BorderLayout());  
        frame.add(northPanel, "North");  
        frame.add(centerSplit, "Center");  
        frame.add(southPanel, "South");  
        frame.setSize(600, 400);  
        //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);// 退出程序  
            }  
        });  
   
        // 文本框按回车键时事件  
        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 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) {  
        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 void run() {  
            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(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());  
                // 反馈连接成功信息  
                writer.println(user.getName() + user.getIp() + "与服务器连接成功!");  
                writer.flush();  
                // 反馈当前在线用户信息  
                if (clients.size() > 0) {  
                    String temp = "";  
                    for (int i = clients.size() - 1; i >= 0; i--) {  
                        temp += (clients.get(i).getUser().getName() + "/" + clients  
                                .get(i).getUser().getIp())  
                                + "@";  
                    }  
                    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();  
                }  
            } catch (IOException e) {  
                e.printStackTrace();  
            }  
        }  
   
        @SuppressWarnings("deprecation")  
        public void run() {// 不断接收客户端的消息,进行处理。  
            String message = null;  
            while (true) {  
                try {  
                    message = reader.readLine();// 接收客户端消息  
                    if (message.equals("CLOSE"))// 下线命令  
                    {  
                        contentArea.append(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();  
                        }  
   
                        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();  
            message = source + "说:" + content;  
            contentArea.append(message + "\r\n");  
            if (owner.equals("ALL")) {// 群发  
                for (int i = clients.size() - 1; i >= 0; i--) {  
                    System.out.println(i);
                    clients.get(i).getWriter().println(message + "(多人发送)");  
                    clients.get(i).getWriter().flush();  
                }  
            }  
        }  
    }  
}

对于客户端,功能分析如下:

1.连接和断开服务器

2.发送和接受信息(所有用户和服务器)

3.显示在线用户

步骤分析如下:

    连接时,判断是否重复连接,若不是重复连接则发送与服务器连接请求,并给服务器发送相应信息(便于服务器增加用户),

并开启接受消息线程,而消息线程要做的就是接受来自服务器和其它客户端线程发送的消息,并判断属于哪类消息,如时服务器关闭或者有新用户上线或者下线和加载在线用户列表的信息,并执行相应操作

package com.example.li;
 
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
 
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.border.TitledBorder;
 
public class Client{  
       
    private JFrame frame;  
    private JList<User> userList;  
    private JTextArea textArea;  
    private JTextField textField;  
    private JTextField txt_port;  
    private JTextField txt_hostIp;  
    private JTextField txt_name;  
    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 static void main(String[] args) {  
        new Client();  
    }  
   
    // 执行发送  
    public void send() {  
        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;  
        }  
        sendMessage(frame.getTitle() + "@" + "ALL" + "@" + message);  
        textField.setText(null);  
    }  
   
    // 构造方法  
    public Client() {  
        textArea = new JTextArea();  
        textArea.setEditable(false);  
        textArea.setForeground(Color.blue);  
        textField = new JTextField();  
        txt_port = new JTextField("6666");  
        txt_hostIp = new JTextField("127.0.0.1");  
        txt_name = new JTextField("xiaoqiang");  
        btn_start = new JButton("连接");  
        btn_stop = new JButton("断开");  
        btn_send = new JButton("发送");  
        listModel = new DefaultListModel();  
        userList = new JList(listModel);  
   
        northPanel = new JPanel();  
        northPanel.setLayout(new GridLayout(1, 7));  
        northPanel.add(new JLabel("端口"));  
        northPanel.add(txt_port);  
        northPanel.add(new JLabel("服务器IP"));  
        northPanel.add(txt_hostIp);  
        northPanel.add(new JLabel("姓名"));  
        northPanel.add(txt_name);  
        northPanel.add(btn_start);  
        northPanel.add(btn_stop);  
        northPanel.setBorder(new TitledBorder("连接信息"));  
   
        rightScroll = new JScrollPane(textArea);  
        rightScroll.setBorder(new TitledBorder("消息显示区"));  
        leftScroll = new JScrollPane(userList);  
        leftScroll.setBorder(new TitledBorder("在线用户"));  
        southPanel = new JPanel(new BorderLayout());  
        southPanel.add(textField, "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.jpg")));  
        frame.setLayout(new BorderLayout());  
        frame.add(northPanel, "North");  
        frame.add(centerSplit, "Center");  
        frame.add(southPanel, "South");  
        frame.setSize(600, 400);  
        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();  
            }  
        });  
   
        // 单击发送按钮时事件  
        btn_send.addActionListener(new ActionListener() {  
            public void actionPerformed(ActionEvent e) {  
                send();  
            }  
        });  
   
        // 单击连接按钮时事件  
        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");// 发送断开连接命令给服务器  
            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() {
            int a= 0;
            String message = "";  
            while (true) {  
                System.out.println(a++);
                try {  
                    message = reader.readLine();  
                    StringTokenizer stringTokenizer = new StringTokenizer(  
                            message, "/@");  
                    String command = stringTokenizer.nextToken();// 命令  
                    if (command.equals("CLOSE"))// 服务器已关闭命令  
                    {  
                        textArea.append("服务器已关闭!\r\n");  
                        closeCon();// 被动的关闭连接  
                        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();  
                }  
            }  
        }  
    }  
}

用户类

package com.example.li;
 
public class User {
    private String name;  
    private String ip;  
   
    public User(String name, String ip) {  
        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;  
    }  
}

猜你喜欢

转载自blog.csdn.net/qq_40511966/article/details/84566523