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

运行

登录界面演示

聊天界面演示

相关推荐
basketball6161 分钟前
Linux C 进程间高级通信
linux·运维·服务器
是小恐龙啊7 分钟前
【测试报告】博客系统(Java+Selenium+Jmeter自动化测试)
运维·服务器
GuGu20249 分钟前
Java异常机制初步理解
java
计算机毕业设计小途10 分钟前
从不会写代码到高分毕设:他用SpringBoot宠物寄领养网站震惊全班,5步搞定,从零到可运行只需120分钟
java·spring boot
LucianaiB10 分钟前
腾讯 iOA 居然出了个完全免费版本【超详细全方位深度体验】
后端
风的归宿5510 分钟前
高性能数据库ClickHouse
后端
林太白14 分钟前
NestJS-菜单模块
前端·后端·nestjs
苦学编程的谢20 分钟前
Mybatis_2
java·开发语言·后端·java-ee·mybatis
KyollBM23 分钟前
【Luogu】每日一题——Day15. P1144 最短路计数 (记忆化搜索 + 图论 + 最短路)
算法·图论