Java实验-Swing 网络聊天室

实验要求:

  1. 综合Swing界面、多线程和Java的网络通信功能,实现仿QQ聊天:

(1)界面设计如下:

(2)要求在服务器端利用多线程响应客户端请求;

// 服务线程(内部类),用于处理客户端的服务线程
class ServerThread extends Thread {}

将每一个请求服务的客户线程对象加入到一个列表中,以便维护整个聊天室内的成员互相通信。

private ArrayList<ServerThread> clientList = null;
// 将该客户加入列表中	
clientList.add(svthread);

代码:

服务端Server.java :

package com.junlin.exer10_;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ScrollPaneConstants;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

/**
 * @Description:
 * @author: junlin623
 * @create: 2022-12-04 9:43
 */
public class Server extends JFrame {
    String name;   //名称
    int port;    //服务器开启的端口号
    JTextArea textArea;  //文本域
    JTextField jTextField;  //发送消息文本框
    ServerSocket server;   //服务端套接字
    PrintWriter pw;     //打印输出流,负责写出服务端的相应数据
    //服务器响应客户端的集合,主要用来将服务器的响应数据发送给所有客户端
    private List<ResponseThread> clientList = new ArrayList<>();

    public Server(String name, int port) {
        super(name);
        this.name = name;
        this.port = port;
        addComponent();   //添加面板中的组件

        try {
            server = new ServerSocket(this.port);
        } catch (IOException e) {
            e.printStackTrace();
        }
        new Thread(new ServerThread()).start();
        textArea.append("服务器已经启动!\n");

        this.setSize(380, 452);
        this.setVisible(true);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    /**
     * 添加组件到面板中
     */
    private void addComponent() {
        Container contentpane = this.getContentPane();
        contentpane.setLayout(new FlowLayout());
        textArea = new JTextArea(20,30);
        jTextField = new JTextField();
        jTextField.setPreferredSize(new Dimension(350, 30));

        //创建滚动面板
        JScrollPane jScrollPane = new JScrollPane(textArea);
        jScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
        jScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);


        JButton sendBtn = new JButton("发送");
        //服务端发送按钮事件绑定
        sendBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                String msg = jTextField.getText();
                textArea.append(name + ": " + msg + "\n");
                sendAll(name + ": " + msg);
                jTextField.setText("");
            }
        });

        //清空记录事件绑定
        JButton clearBtn = new JButton("清空聊天记录");
        clearBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                textArea.setText("");
            }
        });
        contentpane.add(jScrollPane);
        contentpane.add(jTextField);
        contentpane.add(sendBtn);
        contentpane.add(clearBtn);
    }

    //发送消息给所有的客户端
    void sendAll(String msg) {
        if(!"".equals(msg)) {
            for(ResponseThread rt : clientList) {
                rt.send(msg);
            }
        }
    }

    //服务器线程负责与请求的客户端建立连接, 并将与客户端连接的线程加到集合中
    class ServerThread implements Runnable {
        @Override
        public void run() {
            while (true) {
                Socket client = null;
                try {
                    client = server.accept();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                System.out.println("一个客户端建立了连接");
                ResponseThread c = new ResponseThread(client);
                clientList.add(c);     // 管理所有的成员
                new Thread(c).start();
            }
        }
    }

    // 服务线程(内部类),用于处理客户端的服务线程
    class ResponseThread implements Runnable {
        Socket client;   //这个线程就表示与client建立的连接
        BufferedReader br;  //负责读出客户端发送来的数据
        public ResponseThread(Socket client) {
            this.client = client;
            try {
                br = new BufferedReader(new InputStreamReader(this.client.getInputStream()));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        //给本线程中的客户端发送信息
        void send(String msg) {
            try {
                //负责写出服务器发送的数据
                pw = new PrintWriter(this.client.getOutputStream());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            pw.println(msg);
            pw.flush();
        }

        @Override
        public void run() {
            while(true) {
                //接收来自客户端的消息
                String msg = null;
                try {
                    msg = br.readLine();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                if(msg != null && !"".equals(msg.trim())) {
                    textArea.append(msg + "\n");
                    //在服务器端将消息发送给所有的客户端
                    sendAll(msg);
                }
            }
        }
    }
}

客户端Client.java:

package com.junlin.exer10_;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ScrollPaneConstants;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

/**
 * @Description:
 * @author: junlin623
 * @create: 2022-12-04 9:43
 */
public class Client extends JFrame {
    Socket socket;
    String name;
    JTextArea textArea;
    JTextField jTextField;
    PrintWriter pw;
    int port;
    public Client(String name, int port) {
        super(name);
        this.name = name;
        this.port = port;  //表示客户端与服务器建立连接的端口号
        addComponent();

        connectWithServer();
        new Thread(new ReceiveThread(socket)).start();

        this.setSize(380, 452);
        this.setVisible(true);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    /**
     * 与服务器建立连接
     */
    private void connectWithServer() {
        try {
            socket = new Socket("127.0.0.1", port);
            textArea.append(this.name + "已经与服务器建立连接!\n");
            pw = new PrintWriter(this.socket.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 添加组件到面板中
     */
    private void addComponent() {
        Container contentpane = this.getContentPane();
        contentpane.setLayout(new FlowLayout());
        textArea = new JTextArea(20,30);
        jTextField = new JTextField();
        jTextField.setPreferredSize(new Dimension(350, 30));

        //创建滚动面板,并将文本域放入其中
        JScrollPane jScrollPane = new JScrollPane(textArea);
        jScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
        jScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);


        JButton sendBtn = new JButton("发送");
        sendBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                String msg = jTextField.getText();
                jTextField.setText("");
                pw.println(name + ": " + msg);
                pw.flush();
            }
        });
        JButton clearBtn = new JButton("清空聊天记录");
        clearBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                textArea.setText("");
            }
        });
        contentpane.add(jScrollPane);
        contentpane.add(jTextField);
        contentpane.add(sendBtn);
        contentpane.add(clearBtn);
    }

    //客户端接收线程
    class ReceiveThread implements Runnable {
        private Socket client;
        BufferedReader br;  //负责读出数据
        public ReceiveThread(Socket client) {
            this.client = client;
            try {
                InputStreamReader isr = new InputStreamReader(this.client.getInputStream());
                br = new BufferedReader(isr);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        @Override
        public void run() {
            while(true) {
                //接收数据
                try {
                    String msg = br.readLine();
                    if(!"".equals(msg.trim())) {
                        textArea.append(msg + "\n");
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

主类JavaMain.java:

package com.junlin.exer10_;
/**
 * @Description:
 * @author: junlin623
 * @create: 2022-12-03 23:51
 */
public class JavaMain {
    public static void main(String[] args) {
        new Server("服务器", 6666);
        new Client("客户端一", 6666);
        new Client("客户端二", 6666);
    }
}

运行结果:

posted @ 2023-03-06 20:00  junlin623  阅读(358)  评论(0编辑  收藏  举报