使用Java网络编程,窗口,线程,IO,内部类等实现多人在线聊天1.0

news2025/1/20 21:58:16

1.整体思路

思路图

5b3c97a5649f45698a019a67b5c66527.png

整体思路如上: 涉及知识点:线程+网络编程+集合+IO等

 

TCP 协议

d1e074db85854c009a0f3ddcbb83c3cf.png

 2.代码实现过程

服务端

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
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 {//继承窗口来实现窗口功能
    /*设置接受客户端的集合,把接入服务器的客户端存入集合,方便后续的消息转发*/
    ArrayList<Socket> socketsClients = new ArrayList<>();

    /*由于下面线程需要调用窗口的一些东西,所以需要全局变量*/
    JTextArea jTextArea;
    JTextArea jTextSend = new JTextArea(30,20);//只能设置几列
    JButton jButtonSend = new JButton("发送") ;
    public Server() {
        //创建服务器窗口 一些列属性
        //主面板
        JPanel priorPanel = new JPanel(new BorderLayout());

        //显示消息
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);//关闭窗口结束程序
        this.setTitle("来自客户端的消息");
        this.setSize(500, 500);
        jTextArea = new JTextArea();//显示客户端的信息
        jTextArea.setEditable(false);//不可以修改 面板信息

        JScrollPane clientInformation = new JScrollPane(jTextArea);

        priorPanel.add(clientInformation,BorderLayout.CENTER);
        //写一个发布公告的窗口
        JPanel sendPanel = new JPanel();//默认流式布局
        JScrollPane jScrollPane = new JScrollPane(jTextSend);
        jScrollPane.setPreferredSize(new Dimension(400,50));

        sendPanel.add(jScrollPane);
        sendPanel.add(jButtonSend);
        priorPanel.add(sendPanel,BorderLayout.SOUTH);

        this.add(priorPanel);

        //创建监听发送键 
        jButtonSend.addActionListener(new ActionListener() {
        /*用来对每个客户端发送公告*/

            @Override
            public void actionPerformed(ActionEvent e) {
                String announcement = "来自服务器的公告:"+jTextSend.getText()+"\n";
                //把公告发布到聊天界面
                jTextArea.append(announcement);

                /*使用for循环来遍历每个客户端的对象*/
                for(Socket soc:socketsClients){
                    DataOutputStream dataOutputStream = null;
                    try {
                        dataOutputStream = new DataOutputStream(soc.getOutputStream());
                        dataOutputStream.writeUTF(announcement+"\n");
                    } catch (IOException ioException) {
                        ioException.printStackTrace();
                    }
                }
                jTextSend.setText(null);
            }
        });


        this.setVisible(true);
//===================================================================================
//以上为窗口的创建,下面为功能的实现
        try {
            //创建服务器对象 设置端口
            ServerSocket serverSocket = new ServerSocket(9998);
            
            //使用无限循环来不停接受客户端的连接
            while(true){
                Socket socketClient = serverSocket.accept();

                //接收到一个就向集合加入一个客户端
                socketsClients.add(socketClient);
                //就收一个连接就在后台提示一遍
                System.out.println("有"+socketsClients.size()+"个邓钦文连接到服务器!");
                
                //然后启动该客户端的线程  线程的实现则需要我们使用内部类
                new SocketThread(socketClient).start();
            }

            //处理客户端输入的东西

        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("服务器启动失败!");
        }


    }
    //创建监听

    //创建内部类 线程
    class SocketThread extends Thread{
        DataInputStream dataInputStream;
        Socket socket;
        /*构建方法 传入当前客户的连接*/
        public SocketThread(Socket socket) throws IOException {
        /*接受客户端的输入流*/
            dataInputStream = new DataInputStream(socket.getInputStream());
            this.socket = socket;
        }
        /*重写run方法 来实现对客户端的操作方法*/
        @Override
        public void run() {
            while(true){
                try {

                    String msg = dataInputStream.readUTF();
                    /*读取客户端的信息 并打印到自己的窗口上*/
                    jTextArea.append(msg+"\n");
                    //给每一个客户端发送信息  实现群聊的效果
                    for(Socket soc:socketsClients){
                        DataOutputStream dataOutputStream = new DataOutputStream(soc.getOutputStream());
                        dataOutputStream.writeUTF(msg+"\n");
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    System.out.println("读取失败!");
                    socketsClients.remove(socket);
                    return;
                }

            }
        }


    }

}

客户端

登录界面

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 EnterFrame extends JFrame {
    public EnterFrame() throws HeadlessException {

        this.setSize(600,500);
        this.setTitle("欢迎登录");
        this.setResizable(true);
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);//关闭窗口结束程序
        this.setLocationRelativeTo(this);


        JPanel jPanelLast = new JPanel(new GridLayout(4,1));

        //头顶部分
        JPanel jPanelTop = new JPanel();

        JLabel jLabel = new JLabel("欢迎登录");

        jLabel.setFont(new Font("宋体",Font.BOLD,30));

        //中间部分
        JPanel jPanelMiddle = new JPanel(new GridLayout(2,1,0,0));

        JPanel jPanelAccount = new JPanel(new FlowLayout());
        
          //账号密码输入端
        JLabel jLabelAccount = new JLabel("账号");
        JTextField jTextFieldAccount = new JTextField(15);
        jPanelAccount.add(jLabelAccount);
        jPanelAccount.add(jTextFieldAccount);



        JPanel jPanelPassword = new JPanel(new FlowLayout());
        JLabel jLabelPassword = new JLabel("密码");
        JPasswordField jTextFieldPassword = new JPasswordField(15);
        jPanelPassword.add(jLabelPassword);
        jPanelPassword.add(jTextFieldPassword);
        //底部  登录按钮端
        JPanel jPanelFoot = new JPanel();

        JPanel jPanelButton = new JPanel(new FlowLayout());
        JButton enterButton = new JButton("登录");
        JButton signButton = new JButton("注册");
        jPanelButton.add(enterButton);
        jPanelButton.add(signButton);

        jPanelTop.add(jLabel);
        jPanelMiddle.add(jPanelAccount);
        jPanelMiddle.add(jPanelPassword);
        jPanelFoot.add(jPanelButton);

        jPanelLast.add(jPanelTop);
        jPanelLast.add(jPanelMiddle);
        jPanelLast.add(jPanelFoot);


        this.add(jPanelLast);
        this.setVisible(true);
//================================================================================
//以上为登录界面窗口的设计  可以自己设计

//设计监听事件  来判断用户的读取
        enterButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
//1.判断不能为空
                if(jTextFieldAccount.getText().length()<=0||jTextFieldPassword.getText().length()<=0) {
                    JOptionPane.showMessageDialog(null, "输入的账号或密码为空!");
                    return;
                }
//2.输入只能为数字与字母
                if((jTextFieldAccount.getText().matches("[a-zA-Z0-9]*")&&jTextFieldPassword.getText().matches("[a-zA-Z0-9]*"))==false){
                    JOptionPane.showMessageDialog(null,"输入的账号或密码只能为字母和数字");
                    return;
                }

//如果都满足了登录成功 创建 客户端对象 输入服务器地址 与端口  关闭登录界面

                try {
                    Socket socket = new Socket("127.0.0.1", 9998);
                    new ChatFrame(jTextFieldAccount.getText(),socket);
                    dispose();//关闭了登录窗口
                } catch (IOException ioException) {
                    ioException.printStackTrace();
                    JOptionPane.showMessageDialog(null,"无法连接服务器");
                }


            }
        });



    }



}

聊天界面

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;
import java.text.SimpleDateFormat;
import java.util.Date;

public class ChatFrame extends JFrame {
    JTextArea jTextArea;
    public ChatFrame(String account , Socket socket) throws HeadlessException {
        this.setSize(700, 600);
        this.setTitle("欢迎来到"+account+"聊天室");
        this.setResizable(true);
        this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);

        JPanel jPanelEnd = new JPanel( new BorderLayout());//最终面板

        jTextArea = new JTextArea();
        jTextArea.setEditable(false);
        JScrollPane jScrollPane1 = new JScrollPane(jTextArea);
        jPanelEnd.add(jScrollPane1,BorderLayout.CENTER);

        JPanel jPanelInput = new JPanel();
        JTextArea jTextArea2 = new JTextArea(5,40);
        //带滑动的窗口
        JScrollPane jScrollPane2 = new JScrollPane(jTextArea2);//不能通过add加入,只能通过构造方法加入,这样不会出现不显示的问题


        jPanelInput.add(jScrollPane2);

        JButton jButtonSend = new JButton("发送");
        jPanelInput.add(jButtonSend);


        jPanelEnd.add(jPanelInput,BorderLayout.SOUTH);
        this.add(jPanelEnd);

        try {
            new ClientThread(socket).start();
        } catch (IOException e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(null,"发送错误");
        }
//关闭窗口,显示登录窗口
        this.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.out.println("你确定要关闭我妈?");
                int res = JOptionPane.showConfirmDialog(null,"你确定要关闭我吗","操作提示",JOptionPane.OK_CANCEL_OPTION);
                if(res==0){
                    //点击确定
                    new EnterFrame();
                    dispose();//关闭当前对象
                }
            }
        });
        //监听发送事件
        try {
            DataOutputStream socketOutput = new DataOutputStream(socket.getOutputStream());
            String message = socketOutput.toString();
            jButtonSend.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    if(message.length()<=0){
                        JOptionPane.showMessageDialog(null,"输入消息不能为空!");
                        return;
                    }

                    String msg = account+" "+ new SimpleDateFormat("yyyy-MM HH:mm:ss").format(new Date()) +"\n"+jTextArea2.getText();
                    try {
                        socketOutput.writeUTF(msg);
                        System.out.println(msg);
                        jTextArea2.setText("");

                    } catch (IOException ioException) {
                        ioException.printStackTrace();
                        JOptionPane.showMessageDialog(null,"发生错误");
                    }
                }

            });

        } catch (IOException e) {
            e.printStackTrace();
        }

        this.setVisible(true);
//=======================================================================================
//窗口的创建以及窗口功能的实现
    }

//创建内部列 创建客户端的线程,解决多个聊天窗口同时实现
    class ClientThread extends  Thread{
        DataInputStream inputStream;
        Socket socket;
        /*构造方法*/
        public ClientThread(Socket socket) throws IOException {
            inputStream = new DataInputStream(socket.getInputStream());
            this.socket = socket;
        }

        @Override
        public void run() {
            try {
                while(true){
            /*把接受的到信息添加到窗口中*/
                    String msg = inputStream.readUTF();
                    jTextArea.append(msg+"\n");
                }
            } catch (IOException e) {
                e.printStackTrace();
                return;
            }
        }
    }
}

启动程序

public class RunOfServer {
    public static void main(String[] args) {
        new Server();
    }
}
public class RunOfClient {
    public static void main(String[] args) {
        new EnterFrame();
    }
}

3.实现结果

1.启动服务器

16182041264b49778e2ebac0c2d25cf0.png

2.尝试启动 3个客户端  并登录

6c3652a6f8204a21a45bfd4673edef3c.png 5d985973b0ab475eaa8ff03c7b25195d.png

 3.测试消息发送接收以及公告发送功能.

803003105bc245249faa05dd85651dfb.png

4.总结

本次聊天室1.0的简单实现使用了 Java 的网络编程 IO 线程 异常的抛出 集合 内部类 GUI等 

希望指出错误并提供改进意见 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1290455.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

管理和监控CentOS上的HTTP服务

CentOS作为一款稳定的开源服务器操作系统&#xff0c;为各种网络服务提供了优秀的支持。其中&#xff0c;HTTP服务是互联网上最常用的服务之一&#xff0c;它为人们提供了便捷的信息访问和交互方式。在CentOS上管理和监控HTTP服务是一项重要的任务&#xff0c;下面我们将介绍一…

华为数通---BFD多跳检测示例

定义 双向转发检测BFD&#xff08;Bidirectional Forwarding Detection&#xff09;是一种全网统一的检测机制&#xff0c;用于快速检测、监控网络中链路或者IP路由的转发连通状况。 目的 为了减小设备故障对业务的影响&#xff0c;提高网络的可靠性&#xff0c;网络设备需要…

前端“量子纠缠”:multipleWindow3dScene 来了

最近前端实现的量子纠缠在网络上火了起来&#xff0c;作者bgstaal的推文&#xff1a;效果如下&#xff1a; 量子纠缠 那我们一起来看下什么是量子纠缠&#xff0c;以及前端是如何实现的。 什么是量子纠缠&#xff1f; 在量子力学里&#xff0c;当几个粒子在彼此相互作用后&…

【Java】实现顺序表基本的操作(数据结构)

文章目录 前言顺序表1、打印顺序表2、增加元素3、在任意位置增加元素4、判断是否包含某个元素5、查找某个元素对于的位置6、获取任意位置的元素7、将任意位置的元素设为value8、删除第一次出现的关键字9、获取顺序表长度10、清空顺序表总结 前言 在了解顺序表之前我们要先了解…

rust高级 异步编程 二 pin

文章目录 定海神针 Pin 和 Unpin为何需要 PinUnpin深入理解 PinPin 在实践中的运用固定到堆上将固定住的 Future 变为 Unpin总结 定海神针 Pin 和 Unpin 在 Rust 中&#xff0c;所有的类型可以分为两类: 类型的值可以在内存中安全地被移动&#xff0c;例如数值、字符串、布尔…

OpenCV图像相似性比对算法

背景 在做图像处理或者计算机视觉相关的项目的时候&#xff0c;很多时候需要我们对当前获得的图像和上一次的图像做相似性比对&#xff0c;从而找出当前图像针对上一次的图像的差异性和变化点&#xff0c;这需要用到OpenCV中的一些图像相似性和差异性的比对算法&#xff0c;在O…

华为数通---配置端口安全案例

端口安全简介 端口安全&#xff08;Port Security&#xff09;通过将接口学习到的动态MAC地址转换为安全MAC地址&#xff08;包括安全动态MAC、安全静态MAC和Sticky MAC&#xff09;&#xff0c;阻止非法用户通过本接口和交换机通信&#xff0c;从而增强设备的安全性。 组网需…

二百一十三、Flume——Flume拓扑结构介绍

一、目的 最近在看尚硅谷的Flume资料&#xff0c;看到拓扑结构这一块&#xff0c;觉得蛮有意思&#xff0c;于是整理一下Flume的4种拓扑结构 二、拓扑结构 &#xff08;一&#xff09;简单串联 1、结构含义 这种模式是将多个flume顺序连接起来了&#xff0c;从最初的sourc…

一键抠图|3个智能AI抠图软件实现抠图自由!

听说你对如何利用AI抠图技术去除白色背景感兴趣&#xff1f;设想一下&#xff0c;你有一张某人站在白色背景前的照片&#xff0c;而你只希望能留下这个人物。在过去&#xff0c;你可能需要花费大量时间和精力手动进行抠图。但现在&#xff0c;AI技术来拯救你了&#xff01;AI可…

计网实验7

解决&#xff1a;路由器用rip连接&#xff0c;主机通过域名访问&#xff0c;主机之间发送电子邮件 实验步骤 1.搞好部件 2.配好两台主机的ip,掩码&#xff0c;网关 3.连接一下两台主机&#xff0c;由于两台路由器没有连接&#xff0c;所以两台主机也无法连通&#xff0c;丢包率…

搭建个人网盘应用Nextcloud

使用DNF管理软件包 1 使用winscp工具将openeuler-20.03-LTS-x86_64-dvd.iso上传至openeuler虚拟机的/root目录下&#xff0c;然后执行如下命令挂载ISO [rootopenEuler ~]# mount -o loop /root/openEuler-20.03-LTS-everything-x86_64-dvd.iso /mnt/2 添加软件源 [rootope…

智能优化算法应用:基于社交网络算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于社交网络算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于社交网络算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.社交网络算法4.实验参数设定5.算法结果6.参考…

ChatGPT,作为一种强大的自然语言处理模型,具备显著优势,能够帮助您在各个领域取得突破

2023年随着OpenAI开发者大会的召开&#xff0c;最重磅更新当属GPTs&#xff0c;多模态API&#xff0c;未来自定义专属的GPT。微软创始人比尔盖茨称ChatGPT的出现有着重大历史意义&#xff0c;不亚于互联网和个人电脑的问世。360创始人周鸿祎认为未来各行各业如果不能搭上这班车…

vue2+typescript使用高德地图2.0版本

高德地图 webjs api 2.0官网教程 AMap.Driving使用说明 <div class"mmp"><div id"map" ref"mapcontainer"></div></div><script lang"ts"> //安全密钥 window._AMapSecurityConfig{securityJsCode: &qu…

【南京站-EI会议征稿中】第三届网络安全、人工智能与数字经济国际学术会议(CSAIDE 2024)

第三届网络安全、人工智能与数字经济国际学术会议&#xff08;CSAIDE 2024&#xff09; 2024 3rd International Conference on Cyber Security, Artificial Intelligence and Digital Economy 第三届网络安全、人工智能与数字经济国际学术会议&#xff08;CSAIDE 2024&…

〖大前端 - 基础入门三大核心之JS篇㊼〗- BOM基础之window对象

说明&#xff1a;该文属于 大前端全栈架构白宝书专栏&#xff0c;目前阶段免费&#xff0c;如需要项目实战或者是体系化资源&#xff0c;文末名片加V&#xff01;作者&#xff1a;不渴望力量的哈士奇(哈哥)&#xff0c;十余年工作经验, 从事过全栈研发、产品经理等工作&#xf…

SpringBoot3-集成mybatis

1、pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.…

编程过程中出现bug如何应对?

编程过程中出现bug如何应对&#xff1f; 1.找错误原因 如果完全不知道出错的原因&#xff0c;或者说存在着很多错误的有原因&#xff0c;----》控制变量法 例如&#xff0c;昨天我在使用torchrun 多卡并行一个程序的时候&#xff0c;出现了大量的bug, 于是我将报错信息放在网…

uni-app中vue3表单校验失败

目录 1.问题 2.原因及解决方式 3.表单校验方式&#xff08;vue3&#xff09; 1.问题 在app中使用uni-forms表单&#xff0c;并添加校验规则&#xff0c;问题是即使输入内容&#xff0c;表单校验依然失败。 代码&#xff1a; <template><view><uni-forms r…

0基础学java-day14

一、集合 前面我们保存多个数据使用的是数组&#xff0c;那么数组有不足的地方&#xff0c;我们分析一下 1.数组 2 集合 数据类型也可以不一样 3.集合的框架体系 Java 的集合类很多&#xff0c;主要分为两大类&#xff0c;如图 &#xff1a;[背下来] package com.hspedu.c…