Java语言实现网络聊天室

目录

题设:

代码

服务器端功能:

服务器监控界面+服务器接收

服务器端为每一个客户端开启一个线程监听

启动服务器

客户端功能:

登录注册界面

聊天窗口

启动客户端

运行

登录界面演示

聊天界面演示


题设:

多人可以同时聊天

客户端之间是不能之间交互,需要通过服务器端中转

客户端与服务器端聊天交互流程图

代码

服务器端功能:

1、启动服务器端,在服务器端循环监听客户端的连接

2、把循环接收到的多个客户端Socket对象存储起来(集合)

3、在服务器端每个socket都有监听来自客户端向他发送的消息

4、一旦某一个客户端发送了消息,那么在服务器端就将此消息发送给其他客户端

服务器监控界面+服务器接收

java 复制代码
package com.ffyc.chatroomserver;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

public class Server extends JFrame {
    JTextArea displayTextArea;
    //存放所有连接到服务器的socket集合
    ArrayList<Socket> sockets = new ArrayList<>();

    public Server(){
        this.setTitle("聊天室服务器端监控");
        //设置宽高
        this.setSize(500,400);
        //水平垂直居中
        this.setLocationRelativeTo(null);
        //点击关闭按钮时什么都不做
        this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        //设置禁止窗口拖拽调整大小
        this.setResizable(false);

        //最大面板  边界布局
        JPanel jPanel = new JPanel(new BorderLayout());

        //显示聊天内容的面板
        displayTextArea = new JTextArea();
        //设置内容只能靠不能改
        displayTextArea.setEditable(false);
        //用它当作面板
        JScrollPane diaplayScrollPane = new JScrollPane(displayTextArea);
        //添加中间位置  而且自动充满整个区域
        jPanel.add(diaplayScrollPane);

        //发送聊天内容面板
        JPanel sendPanel = new JPanel();
        JTextArea sendTextArea = new JTextArea(3,30);
        sendTextArea.setLineWrap(true);
        JScrollPane sendScrollPane = new JScrollPane(sendTextArea);

        JButton sendButton = new JButton("发送公告");
        sendPanel.add(sendScrollPane);
        sendPanel.add(sendButton);
        jPanel.add(sendPanel, BorderLayout.SOUTH);

        this.add(jPanel);

        this.setVisible(true);

        sendButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                //获取的是通知公告内容
                String notice = sendTextArea.getText();
                for(Socket soc:sockets){
                    DataOutputStream dataOutputStream = null;
                    try {
                        dataOutputStream = new DataOutputStream(soc.getOutputStream());
                        dataOutputStream.writeUTF("来自服务器的通知:"+notice);
                    } catch (IOException ioException) {
                        ioException.printStackTrace();
                    }
                 }
            }
        });
    }

    //启动服务器
    public void startServer(){
        try {
            //启动服务
            ServerSocket serverSocket = new ServerSocket(9999);
            System.out.println("服务器启动成功");
            //监听客户端连接,监听多个客户端连接
            while (true){
                //监听客户端的连接
                Socket socket = serverSocket.accept();
                //加入集合
                sockets.add(socket);
                System.out.println("有客户端连接,连接数量为:" + sockets.size());

                //为每一个连接到服务器的客户端开启一个线程
                new SocketThread(socket).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("服务器启动失败");
        }
    }

    //创建一个内部类,继承Thread类,用来监听自己客户端有没有发送消息
    class SocketThread extends Thread{
        boolean mark = true;
        DataInputStream dataInputStream;
        Socket socket;
        public SocketThread(Socket socket) throws IOException {
            this.socket = socket;
            dataInputStream = new DataInputStream(socket.getInputStream());
        }

        @Override
        public void run() {
            //一直死循环,监听客户端发送的消息
            while (mark){
                try {
                    String msg = dataInputStream.readUTF();
                    displayTextArea.append(msg+"\n");
                    System.out.println(msg);
                    //向不同的客户端转发消息
                    //遍历socket集合 A B C
                    for(Socket soc:sockets){
                        DataOutputStream dataOutputStream = new DataOutputStream(soc.getOutputStream());
                        dataOutputStream.writeUTF(msg);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    System.out.println("客户端下线了!");
                    sockets.remove(socket);
                    //停止循环监听
                    mark = false;
                }
            }
        }
    }
}
服务器端为每一个客户端开启一个线程监听

启动服务器

java 复制代码
package com.ffyc.chatroomserver;

public class ServerRun {
    public static void main(String[] args) {
        new Server().startServer();
    }
}

客户端功能:

1、用户登录(只需要账号不为空即可),创建socket

2、如果socket创建成功,打开聊天窗口

3、输入内容点击发送按钮发送消息

4、在客户端监听服务器端发送回来的消息,并把消息显示出来

登录注册界面

java 复制代码
package com.ffyc.chatroomclient.frame;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.Socket;

public class LoginFrame extends JFrame {
    public LoginFrame(){
        this.setTitle("欢迎登录");
        //设置宽高
        this.setSize(500,400);
        //水平垂直居中
        this.setLocationRelativeTo(null);
        //关闭窗口时退出程序
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        //设置禁止窗口拖拽调整大小
        this.setResizable(false);
        //最大的面板  网格布局  4行1列
        JPanel jPanel = new JPanel(new GridLayout(4,1));
        //欢迎面板
        JPanel welcomePanel = new JPanel();
        JLabel welcomeLabel = new JLabel("欢迎登录");
        welcomeLabel.setFont(new Font("宋体", Font.BOLD, 35));
        welcomeLabel.setForeground(Color.black);
        welcomePanel.add(welcomeLabel);

        //账号面板
        JPanel accountPanel = new JPanel();
        JLabel accountLabel = new JLabel("账号");
        JTextField accountField = new JTextField(15);
        accountPanel.add(accountLabel);
        accountPanel.add(accountField);

        //密码面板
        JPanel passwordPanel = new JPanel();
        JLabel passwordLabel = new JLabel("密码");
        JPasswordField passwordField = new JPasswordField(15);
        passwordPanel.add(passwordLabel);
        passwordPanel.add(passwordField);

        //登录面板
        JPanel buttonPanel = new JPanel();
        JButton loginButton = new JButton("登录");
        JButton regButton = new JButton("注册");
        buttonPanel.add(loginButton);
        buttonPanel.add(regButton);

        jPanel.add(welcomePanel);
        jPanel.add(accountPanel);
        jPanel.add(passwordPanel);
        jPanel.add(buttonPanel);

        this.add(jPanel);
        //让窗口显示  放在设置的最后一行
        this.setVisible(true);

        //为登录按钮添加事件监听
        loginButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                //获得账号和密码
                String account = accountField.getText();
                String password = new String(passwordField.getPassword());
                if(account.length()==0){
                    JOptionPane.showMessageDialog(null, "账号不能为空!");
                    return;
                }
                if(password.length()==0){
                    JOptionPane.showMessageDialog(null, "密码不能为空!");
                    return;
                }
                //后期预留与数据库交互

                //创建Socket
                try {
                    Socket socket = new Socket("127.0.0.1",9999);
                    //创建聊天窗口
                    new ChatFrame(account,socket);
                    //释放窗口
                    dispose();
                } catch (IOException ioException) {
                    ioException.printStackTrace();
                    JOptionPane.showMessageDialog(null, "服务器连接失败,请稍后再试!");
                }
            }
        });
    }
}

聊天窗口

java 复制代码
package com.ffyc.chatroomclient.frame;

import com.ffyc.chatroomclient.util.DateUtil;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;

public class ChatFrame extends JFrame{

    JTextArea displayTextArea;

    public ChatFrame(String account, Socket socket) throws IOException {
        DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());

        this.setTitle("欢迎"+account+"登录");
        //设置宽高
        this.setSize(500,400);
        //水平垂直居中
        this.setLocationRelativeTo(null);
        //点击关闭按钮时什么都不做
        this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        //设置禁止窗口拖拽调整大小
        this.setResizable(false);

        //最大面板  边界布局
        JPanel jPanel = new JPanel(new BorderLayout());

        //显示聊天内容的面板
        displayTextArea = new JTextArea();
        //设置内容只能靠不能改
        displayTextArea.setEditable(false);
        //用它当作面板
        JScrollPane diaplayScrollPane = new JScrollPane(displayTextArea);
        //添加中间位置  而且自动充满整个区域
        jPanel.add(diaplayScrollPane);

        //发送聊天内容面板
        JPanel sendPanel = new JPanel();
        JTextArea sendTextArea = new JTextArea(3,35);
        sendTextArea.setLineWrap(true);
        JScrollPane sendScrollPane = new JScrollPane(sendTextArea);

        JButton sendButton = new JButton("发送");
        sendPanel.add(sendScrollPane);
        sendPanel.add(sendButton);
        jPanel.add(sendPanel,BorderLayout.SOUTH);

        this.add(jPanel);
        this.setVisible(true);

        //来到聊天窗口后,可以开启一个线程监听服务器端发送的消息
        new ClientThread(socket).start();

        //为发送按钮添加事件监听
        sendButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                String message = sendTextArea.getText();
                if(message.length() == 0){
                    JOptionPane.showMessageDialog(null, "发送内容不能为空!");
                    return;
                }
                //不为空,向服务器端发送此消息
                String msg = account+" "+ DateUtil.dateToString("yyyy-MM-dd HH:mm:ss")+"\n";
                msg += message;
                try {
                    //发送消息
                    dataOutputStream.writeUTF(msg);
                    //清空发送框
                    sendTextArea.setText("");

                } catch (IOException ioException) {
                    ioException.printStackTrace();
                    JOptionPane.showMessageDialog(null, "内容发送失败!请检查网络是否异常");
                }
            }
        });

        //为窗口添加事件监听
        this.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                int res = JOptionPane.showConfirmDialog(null, "是否退出聊天", "操作提示", JOptionPane.OK_CANCEL_OPTION);
                if(res == 0){
                    //点击确认
                    new LoginFrame();
                    //释放聊天窗口
                    dispose();
                }
            }
        });
    }

    //线程监听服务器发送的消息
    class ClientThread extends Thread{
        boolean mark = true;
        DataInputStream dataInputStream;
        public ClientThread(Socket socket) throws IOException {
            dataInputStream = new DataInputStream(socket.getInputStream());
        }

        @Override
        public void run() {
            while (mark){
                try {
                    String msg = dataInputStream.readUTF();
                    //显示聊天内容,追加  保留之前的内容
                    displayTextArea.append(msg+"\n");
                } catch (IOException e) {
                    e.printStackTrace();
                    //停止循环监听
                    mark = false;
                }
            }
        }
    }
}

启动客户端

java 复制代码
package com.ffyc.chatroomclient.frame;

public class ClientRun {
    public static void main(String[] args) {
        new LoginFrame();
    }
}

运行

登录界面演示

聊天界面演示

相关推荐
yuanbenshidiaos2 分钟前
C++----------函数的调用机制
java·c++·算法
唐叔在学习6 分钟前
【唐叔学算法】第21天:超越比较-计数排序、桶排序与基数排序的Java实践及性能剖析
数据结构·算法·排序算法
程序员_三木10 分钟前
Three.js入门-Raycaster鼠标拾取详解与应用
开发语言·javascript·计算机外设·webgl·three.js
是小崔啊20 分钟前
开源轮子 - EasyExcel01(核心api)
java·开发语言·开源·excel·阿里巴巴
ALISHENGYA26 分钟前
全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之分支结构(switch语句)
数据结构·算法
tianmu_sama26 分钟前
[Effective C++]条款38-39 复合和private继承
开发语言·c++
chengooooooo27 分钟前
代码随想录训练营第二十七天| 贪心理论基础 455.分发饼干 376. 摆动序列 53. 最大子序和
算法·leetcode·职场和发展
黄公子学安全29 分钟前
Java的基础概念(一)
java·开发语言·python
liwulin050630 分钟前
【JAVA】Tesseract-OCR截图屏幕指定区域识别0.4.2
java·开发语言·ocr
jackiendsc34 分钟前
Java的垃圾回收机制介绍、工作原理、算法及分析调优
java·开发语言·算法