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

运行

登录界面演示

聊天界面演示

相关推荐
SharkWeek.32 分钟前
【力扣Hot 100】普通数组2
数据结构·算法·leetcode
敲上瘾32 分钟前
动静态库的制作与使用(Linux操作系统)
linux·运维·服务器·c++·系统架构·库文件·动静态库
周山至水数翠峰40 分钟前
.net 如何处理网页的Json请求?
服务器·json·.net
漫漫进阶路5 小时前
VS C++ 配置OPENCV环境
开发语言·c++·opencv
陈平安Java and C5 小时前
MyBatisPlus
java
秋野酱5 小时前
如何在 Spring Boot 中实现自定义属性
java·数据库·spring boot
安的列斯凯奇6 小时前
SpringBoot篇 单元测试 理论篇
spring boot·后端·单元测试
Bunny02126 小时前
SpringMVC笔记
java·redis·笔记
架构文摘JGWZ6 小时前
FastJson很快,有什么用?
后端·学习
BinaryBardC6 小时前
Swift语言的网络编程
开发语言·后端·golang