当前位置: 首页 > news >正文

Java利用UDP实现简单群聊

一、创建新项目
首先新建一个新的项目,并按如下操作

二、实现代码
界面ChatFrame类
package 群聊;
 
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.net.InetAddress;
 
public abstract class ChatFrame extends JFrame {
    private JTextArea receiveArea = new JTextArea();//接收文本框,用来显示服务器发送过来的文本
    private JTextArea sendArea = new JTextArea();//发送文本框,用来显示当前用户要发送的文本
 
    private JButton sendBtn = new JButton("SEND");//发送按键
 
    public ChatFrame() {
        this.initFrame();//初始化窗口
        this.initComponent();//初始化组件
        this.initListener();//初始化监听器
        this.receive();//开启监听服务器线程,把接收到的文本显示在receiveArea中
    }
 
    // 初始化监听器
    private void initListener() {
        // 给发送按键添加监听器,当被点击时调用send()方法
        sendBtn.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                send();
            }
        });
 
        // 给发送文本框添加键盘监听器,当按下Ctrl+ENTER时调用send()方法
        sendArea.addKeyListener(new KeyAdapter() {
            public void keyPressed(KeyEvent e) {
                if(e.isControlDown()) {
                    if(e.getKeyCode() == KeyEvent.VK_ENTER) {
                        send();
                    }
                }
            }
        });
    }
 
    // 子类需要重写本方法
    // 在本方法中使用socket实现消息发送
    public abstract void sendText(String text);
 
    // 子类需要重写本方法
    // 在本方法中启动监听服务器线程,调用本类receiveText(String)把接收到的文本显示出来
    public abstract void receive();
 
    // 本方法用来发送文本
    public void send() {
        // 如果发送文本框中没有文本,弹出警告对话框
        if(sendArea.getText().equals("")) {
            javax.swing.JOptionPane.showMessageDialog(this, "空文本不能发送!");
            sendArea.requestFocus();// 把光标归还给发送文本框
            return;
        }
 
        // 调用子类的方法完成文本发送
        sendText(sendArea.getText());
        // 把发送文本框内容清空
        sendArea.setText(null);
    }
 
    // 本方法完成接收服务器消息的后续工作-在文本框中显示服务器消息,子类的receive()方法在接收服务器消息后可以调用本方法
    public void receiveText(String text) {
        receiveArea.append(text);//把接收到的消息添加到文本框中
        // 设置光标位置到最后,如果不设置滚动条不动
        receiveArea.setCaretPosition(receiveArea.getText().length());
    }
 
    // 初始化组件
    private void initComponent() {
        // 使用接收文本框创建滚动窗口(把文本框添加到了滚动窗口中),总是显示纵向滚动条,永不显示横向滚动条
        JScrollPane sp1 = new JScrollPane(receiveArea, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
                JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        // 设置滚动窗口大小、位置、无边框;并把滚动窗口添加到主窗口中
        sp1.setSize(606, 350);
        sp1.setLocation(14, 20);
        sp1.setBorder(null);
        this.add(sp1);
 
        // 设置接收文本框背景色、不可编辑、自动换行
        receiveArea.setBackground(new Color(238, 238, 238));
        receiveArea.setEditable(false);
        receiveArea.setLineWrap(true);
 
        // 创建发送文本框的滚动窗口,设置自动换行、大小、位置,然后添加到主窗口中
        JScrollPane sp2 = new JScrollPane(sendArea, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
                JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        sendArea.setLineWrap(true);
        sp2.setSize(606, 145);
        sp2.setLocation(14, 400);
        this.add(sp2);
 
        // 设置发送按键的大小、位置,并添加到主窗口中
        sendBtn.setSize(68, 21);
        sendBtn.setLocation(553, 560);
        this.add(sendBtn);
 
        // 设置主窗口的标题为当前IP地址
        try {
            this.setTitle(InetAddress.getLocalHost().getHostAddress());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
 
    // 初始化主窗口
    private void initFrame() {
        // 设置主窗口的大小、布局管理器为空、背景色、位置、大小不可改变
        this.setSize(640, 620);
        this.setLayout(null);
        this.setBackground(new Color(246, 246, 247));
        this.setLocation(350, 50);
        this.setResizable(false);
 
        // 设置主窗口的“X”按钮点击后结束程序
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
 
    // 显示主窗口方法
    public void setVisible(boolean b) {
        super.setVisible(b);//调用父类的显示方法
        sendArea.requestFocus();//让发送文本框得到焦点
    }
}

组播聊天SocketChat类
package 群聊;
 
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.util.Date;
 
/**
 * 本类继承了ChatFrame,ChatFrame实现了GUI显示
 * 本类负责使用MulticastSocket完成群聊的发送消息与接收消息
 */
public class SocketChat extends ChatFrame {
    private MulticastSocket socket;//群组Socket
 
    public SocketChat() throws IOException {
        socket = new MulticastSocket(54321);//创建群组Socket,绑定54321端口
        //加入虚拟IP:235.235.235.235指定的群组中。虚拟IP范围是:224.0.0.1 和 239.255.255.255
        //加入群组后,就可以接收群组的消息,也可以向群组发送消息了
        socket.joinGroup(InetAddress.getByName("235.235.235.235"));
    }
 
    // 发送消息方法
    public void sendText(String text) {
        try {
            // 获取IP地址
            String ip = InetAddress.getLocalHost().getHostAddress();
            // 获取当前时间格式化字符串
            String time = String.format(" <====> %tF %<tT", new Date());
            // 把IP、时间,以及要发送的文本连接在一起
            text = ip + time + "\n" + text + "\n\n";
            // 把文本转换成字节数组
            byte[] buff = text.getBytes();
            // 使用socket向群组发送,socket的send()方法需要两个参数:DatagramPacket、端口号
            // DatagramPacket表示数据包,创建它需要三个参数:数据包的内容、数据包的字节数、要发送的IP地址
            socket.send(new DatagramPacket(buff, buff.length, InetAddress.getByName("235.235.235.235"), 54321));
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
 
    // 本方法用来接收群组发送过来的消息
    public void receive() {
        // 创建监听群组消息的线程,并启动它
        new Thread() {
            public void run() {
                // 循环监听
                while(true) {
                    try {
                        // 创建数据包的字节数组,大小为1KB
                        byte[] buff = new byte[1024];
                        // 创建数据包
                        DatagramPacket dp = new DatagramPacket(buff, buff.length);
                        // 接收群组发送过来的消息到数据包中
                        // 本方法会阻塞当前线程,直到接收到消息为止
                        socket.receive(dp);
                        // 把接收到的消息转换成字符串
                        String text = new String(dp.getData(), 0, dp.getLength());
                        // 调用父类的方法完成显示
                        receiveText(text);
                    } catch(Exception e) {}
                }
            }
        }.start();
    }
 
    public static void main(String[] args) throws IOException {
        SocketChat sc = new SocketChat();
        sc.setVisible(true);
    }
}

三、运行结果


运行的第一个窗口成员1

第二个窗口为成员2

第三个窗口为成员3

由此可见、新建窗口=添加成员
 

相关文章:

Java利用UDP实现简单群聊

一、创建新项目 首先新建一个新的项目&#xff0c;并按如下操作 二、实现代码 界面ChatFrame类 package 群聊; import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.net.InetAddress; public abstract class ChatFrame extends JFrame { p…...

fastapi.templating与HTMLResponse

要声明一个模板对象&#xff0c;应将存储html模板的文件夹作为参数提供。在当前工作目录中&#xff0c;我们将创建一个 “templates “目录。 templates Jinja2Templates(directory“templates”) 我们现在要把这个页面的HTML代码渲染成HTMLResponse。让我们修改一下hello()函…...

当初为什么选择计算机这类的行业?

CSDN给了这么一个话题&#xff1a; 还记得当初自己为什么选择计算机&#xff1f; 当初你问我为什么选择计算机&#xff0c;我笑着回答&#xff1a;“因为我梦想成为神奇的码农&#xff01;我想像编织魔法一样编写程序&#xff0c;创造出炫酷的虚拟世界&#xff01;”谁知道&…...

tif文件转png、Excel

l利用gdal读取tif中的地理信息和波段数组&#xff0c;然后保存想要的格式即可。 from osgeo import gdal from PIL import Image import numpy as np import cv2 as cv from matplotlib import pyplot as plt# 读取.tif文件 def read_tif(file_path):dataset gdal.Open(file_…...

【PyTorch】训练过程可视化

文章目录 1. 训练过程中的可视化1.1. alive_progress1.2. rich.progress 2. 训练结束后的可视化2.1. tensorboardX2.1.1. 安装2.1.2. 使用 1. 训练过程中的可视化 主要是监控训练的进度。 1.1. alive_progress 安装 pip install alive_progress使用 from alive_progress i…...

深入理解Go语言GC机制

1、Go 1.3之前的标记-清除&#xff08;mark and sweep&#xff09;算法 Go 1.3之前的时候主要用的是普通的标记-清除算法&#xff0c;此算法主要由两个主要的步骤&#xff1a; 标记&#xff08;Mark phase&#xff09;清除&#xff08;Sweep phase&#xff09; 1&#xff09…...

qt-C++笔记之组件-分组框QGroupBox

qt-C笔记之组件-分组框QGroupBox code review! 文章目录 qt-C笔记之组件-分组框QGroupBox1.《Qt 6 C开发指南》p752.《Qt 官方文档》3.《Qt 5.12实战》——5.9 分组框控件 1.《Qt 6 C开发指南》p75 2.《Qt 官方文档》 中间段落翻译&#xff1a; 我把示例补充完整&#xff1a; …...

qt 定时器用法

在qt开发中&#xff0c;定时器是我们经常用到的。我们接下来说一下定时器的三种用法&#xff0c;需要注意的是定时器事件是在主线程中触发的&#xff0c;因此在处理耗时操作时应特别小心&#xff0c;以避免阻塞应用程序的事件循环。 1. 三种定时器使用 1.1 QObject的定时器 …...

用23种设计模式打造一个cocos creator的游戏框架----(九)访问者模式

1、模式标准 模式名称&#xff1a;访问者模式 模式分类&#xff1a;行为型 模式意图&#xff1a;将数据操作与数据结构分离&#xff0c;使得在不修改数据结构的前提下&#xff0c;可以添加或改变对数据的操作。 结构图&#xff1a; 适用于&#xff1a; 当你需要对一个复杂对…...

根文件系统初步测试

一. 简介 上一篇文章学习了向所编译生成的根文件系统中加入 lib库文件。文章地址如下&#xff1a; 根文件系统lib库添加与初步测试-CSDN博客 本文继上一篇文章的学习&#xff0c;本文对之前制作的根文件系统进行一次初步测试。 二. 根文件系统初步测试 为了方便测试&#…...

【精选】设计模式——策略设计模式-两种举例说明,具体代码实现

Java策略设计模式 简介 策略设计模式是一种行为型设计模式&#xff0c;它允许在运行时选择算法的行为。 在软件开发中&#xff0c;我们常常需要根据不同情况采取不同的行为。通常的做法是使用大量的条件语句来实现这种灵活性&#xff0c;但这会导致代码变得复杂、难以维护和扩…...

外包干了3个月,技术倒退2年。。。

先说情况&#xff0c;大专毕业&#xff0c;18年通过校招进入湖南某软件公司&#xff0c;干了接近6年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试&#xf…...

微信小程序:chooseimage从本地相册选择图片或使用相机拍照

文档 https://uniapp.dcloud.net.cn/api/media/image.html#chooseimage https://developers.weixin.qq.com/miniprogram/dev/api/media/image/wx.chooseImage.html 代码示例 const res await uni.chooseImage({count: 1, //默认9sizeType: [original, compressed], //可以…...

「Swift」取消UITableView起始位置在状态栏下方开始

前言&#xff1a;在写页面UI时发现&#xff0c;当隐藏了NavigationBar时&#xff0c;即使UITableView是从(0,0)进行布局&#xff0c;也会一直在手机状态栏下方进行展示布局&#xff0c;而我的想法是希望UITableView可以从状态栏处就进行展示布局 当前页面展示&#xff1a; 问题…...

android高版本适配使用Tools.java

随着android版本的提升&#xff0c;原生Tools不公开并且不能被正常使用&#xff0c;为了延续项目的功能&#xff0c;修改如下&#xff1a; /** Copyright (C) 2006 The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License&quo…...

面试官:说说webpack中常见的Loader?解决了什么问题?

面试官&#xff1a;说说webpack中常见的Loader&#xff1f;解决了什么问题&#xff1f; 一、是什么 loader 用于对模块的"源代码"进行转换&#xff0c;在 import 或"加载"模块时预处理文件 webpack做的事情&#xff0c;仅仅是分析出各种模块的依赖关系&a…...

【蓝桥杯省赛真题50】Scratch智能计价器 蓝桥杯scratch图形化编程 中小学生蓝桥杯省赛真题讲解

目录 scratch智能计价器 一、题目要求 编程实现 二、案例分析 1、角色分析...

折半查找(数据结构实训)

题目&#xff1a; 标准输入输出 题目描述&#xff1a; 实现折半查找。要求查找给定的值在数据表中相应的存储位置。本题目假定输入元素均按非降序输入。 输入&#xff1a; 输入包含若干个测试用例&#xff0c;第一行为测试用例个数k。每个测试用例占3行&#xff0c;其中第一行为…...

AR助推制造业智能转型:实时远程协作与可视化引领生产创新

制造商面临着多方面的变革&#xff0c;技术的兴起催生了工业物联网&#xff08;IIoT&#xff09;&#xff0c;改变了现代工厂的外貌、系统和流程。同时&#xff0c;全球竞争压力和不断变化的员工队伍要求采用新的员工培训方法&#xff0c;并重新审视工人在工厂中的角色。尽管如…...

【用unity实现100个游戏之18】从零开始制作一个类CSGO/CS2、CF第一人称FPS射击游戏——基础篇3(附项目源码)

文章目录 本节最终效果前言素材人物移动音效枪口火焰和开火音效枪口灯光弹孔和火花添加武器随镜头手臂摇摆效果源码完结 本节最终效果 前言 本节主要实现添加音效&#xff0c;和一些特效、武器摆动调整。 素材 素材&#xff0c;为了方便我直接用了unity免费的音效输出&#…...

脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)

一、数据处理与分析实战 &#xff08;一&#xff09;实时滤波与参数调整 基础滤波操作 60Hz 工频滤波&#xff1a;勾选界面右侧 “60Hz” 复选框&#xff0c;可有效抑制电网干扰&#xff08;适用于北美地区&#xff0c;欧洲用户可调整为 50Hz&#xff09;。 平滑处理&…...

Unity3D中Gfx.WaitForPresent优化方案

前言 在Unity中&#xff0c;Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染&#xff08;即CPU被阻塞&#xff09;&#xff0c;这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案&#xff1a; 对惹&#xff0c;这里有一个游戏开发交流小组&…...

2025年能源电力系统与流体力学国际会议 (EPSFD 2025)

2025年能源电力系统与流体力学国际会议&#xff08;EPSFD 2025&#xff09;将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会&#xff0c;EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...

多场景 OkHttpClient 管理器 - Android 网络通信解决方案

下面是一个完整的 Android 实现&#xff0c;展示如何创建和管理多个 OkHttpClient 实例&#xff0c;分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八

现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet&#xff0c;点击确认后如下提示 最终上报fail 解决方法 内核升级导致&#xff0c;需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

关于nvm与node.js

1 安装nvm 安装过程中手动修改 nvm的安装路径&#xff0c; 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解&#xff0c;但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后&#xff0c;通常在该文件中会出现以下配置&…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek

文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama&#xff08;有网络的电脑&#xff09;2.2.3 安装Ollama&#xff08;无网络的电脑&#xff09;2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...

作为测试我们应该关注redis哪些方面

1、功能测试 数据结构操作&#xff1a;验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化&#xff1a;测试aof和aof持久化机制&#xff0c;确保数据在开启后正确恢复。 事务&#xff1a;检查事务的原子性和回滚机制。 发布订阅&#xff1a;确保消息正确传递。 2、性…...

如何应对敏捷转型中的团队阻力

应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中&#xff0c;明确沟通敏捷转型目的尤为关键&#xff0c;团队成员只有清晰理解转型背后的原因和利益&#xff0c;才能降低对变化的…...

高效的后台管理系统——可进行二次开发

随着互联网技术的迅猛发展&#xff0c;企业的数字化管理变得愈加重要。后台管理系统作为数据存储与业务管理的核心&#xff0c;成为了现代企业不可或缺的一部分。今天我们要介绍的是一款名为 若依后台管理框架 的系统&#xff0c;它不仅支持跨平台应用&#xff0c;还能提供丰富…...