Java利用UDP实现简单群聊

2023-12-13 04:45:33

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

二、实现代码
界面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

由此可见、新建窗口=添加成员
————————————————
版权声明:本文为CSDN博主「Mr.寒风」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/2301_76534800/article/details/134838262

文章来源:https://blog.csdn.net/zhangchenyu66/article/details/134841983
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。