欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

荐 Java基于UDP的GUI界面简易聊天室课程实验(获取本机IP、IDEA同个程序运行两次设置方法)

程序员文章站 2022-03-11 15:13:13
项目阐述基于UDP协议编写一个GUI界面的简易聊天室UDP通信协议优点:传输速度快,安全性高原因:不同于TCP的三次握手协议,UDP是一个无状态的传输协议,因此传输数据非常快;由于没有TCP的确认机制、三次握手机制等多种机制,因此相对较为安全,但并不是绝对安全。缺点:不可靠,只负责发送,不负责一定“送”到适用于对数据传输速度要求较高,质量不高的场合,如:视频、通讯、游戏等......

1、效果图

荐
                                                        Java基于UDP的GUI界面简易聊天室课程实验(获取本机IP、IDEA同个程序运行两次设置方法)
荐
                                                        Java基于UDP的GUI界面简易聊天室课程实验(获取本机IP、IDEA同个程序运行两次设置方法)

2、项目开发

本程序使用到的所有类、方法以及内部类:

  • public class UDPChat extends JFrame{};
  • public class UDPChatFace extends JPanel implements ActionListener{}:
    • public void init(){};
    • private void sendMessage(byte[] data){};
    • private void send(){};
    • private class Receive extends Thread{};
    • public void actionPerformed(ActionEvent e) {};

2.1、项目阐述

基于UDP协议编写一个GUI界面的简易聊天室
开发软件:IDEA

2.2、项目思路

利用UDP协议进行信息的传输与接收,由于聊天室属于即时通讯,所以必须做到同时接收与发送,因此可以考虑利用多线程完成该目的。

2.3、项目涉及知识点

  • GUI界面知识
  • UDP协议
  • 多线程

2.4、UDP通信协议

  • 优点:传输速度快,安全性高
    原因:不同于TCP的三次握手协议,UDP是一个无状态的传输协议,因此传输数据非常快;由于没有TCP的确认机制、三次握手机制等多种机制,因此相对较为安全,但并不是绝对安全。
  • 缺点:不可靠,只负责发送,不负责一定“送”到
  • 适用于对数据传输速度要求较高,质量不高的场合,如:视频、通讯、游戏等

2.5、GUI界面设计

使用到的组件: JPanel、JScrollPane、JLabel、JTextField、JTextArea、JButton

public class UDPChatFace extends JPanel implements ActionListener {

    //创建变量
    JPanel panel_1;
    JPanel panel_2;
    JPanel panel_3;
    JScrollPane panel_2_1;//滚动面板显示聊天记录
    JPanel panel_2_2;

    JLabel label1;//监听
    JLabel label2;//ip
    JLabel label3;//端口

    JTextField textField_ip;//ip输入
    JTextField textField_port;//端口号输入

    JTextArea textArea_history;//聊天记录文本域
    JTextArea textArea_message;//输入文字信息文本域

    JButton button_concern;
    JButton button_send;
    JButton button_clear;

    //端口设置
    //一般设置在8000以上,8000以下的端口号大部分被占用
    private int localPort = 10001;//本地端口
    private int otherPort = 10002;//对方端口

    private String ip;

    String message;//输入框信息
    private DatagramSocket socket;


    public UDPChatFace(){
        init();
    }

    public void init(){
        //添加组件
        panel_1 = new JPanel();
        panel_2 = new JPanel();
        panel_3 = new JPanel();

        textArea_history = new JTextArea(40,68);//设置聊天记录框的大小
        textArea_history.setEditable(false);//设置聊天记录框不可输入
        textArea_message = new JTextArea(13,70);
        textArea_message.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {  //键盘监听事件,实现文本框输入后,按回车消息发送的功能
                if (e.getKeyCode() == KeyEvent.VK_ENTER){
                    if (textArea_message.getText().equals("")){
                        JOptionPane.showMessageDialog(panel_1,"不可发送空白信息!"); //弹窗
                        return;
                    }else {
                        send(); //发送消息
                    }
                }
            }
        });

        panel_2_1 = new JScrollPane(textArea_history); //将"聊天记录"输入框加入滚动面板中
        panel_2_1.setBorder(BorderFactory.createTitledBorder("聊天记录"));//边框设置
        panel_2_2 = new JPanel();
        panel_2_2.setBorder(BorderFactory.createTitledBorder("请输入文字:"));//边框设置

        String str = "正在监听****端口";//标签
        label1 = new JLabel(str,JLabel.RIGHT);//靠右对齐
        label2 = new JLabel("请输入对方IP:",JLabel.RIGHT);
        label3 = new JLabel("请输入对方端口号:",JLabel.RIGHT);

        textField_ip = new JTextField(5);
        textField_port = new JTextField(5);

        //绑定事件
        button_send = new JButton("发送");
        button_send.addActionListener(this);
        button_clear = new JButton("清空");
        button_clear.addActionListener(this);
        button_concern = new JButton("确定");
        button_concern.addActionListener(this);

        setLayout(new BorderLayout());
        add(panel_1,BorderLayout.NORTH);
        add(panel_2,BorderLayout.CENTER);
        add(panel_3,BorderLayout.SOUTH);

        panel_1.setLayout(new FlowLayout());
        panel_1.add(label1);

        panel_2.setLayout(new GridLayout(2,1));
        panel_2.add(panel_2_1);
        panel_2.add(panel_2_2);

        panel_2_2.add(textArea_message);

        panel_3.setLayout(new FlowLayout());
        panel_3.add(label2);
        panel_3.add(textField_ip);
        panel_3.add(label3);
        panel_3.add(textField_port);
        panel_3.add(button_concern);
        panel_3.add(button_send);
        panel_3.add(button_clear);
		
		......

    }

2.6、功能实现

2.6.1、“确定”按钮

功能:实现对方IP以及端口号的输入,建立聊天,同时开启接收信息的监听线程

//监听事件
    @Override
    public void actionPerformed(ActionEvent e) {

        Object source = e.getSource();


        if (button_send.equals(source)){//发送
            ......
        }else if (button_clear.equals(source)){//清空
            ......
        }else if (button_concern.equals(source)){//确定

            if (textField_ip.getText().equals("") || textField_port.getText().equals("")){
                JOptionPane.showMessageDialog(this,"未正确输入IP及端口号!");//弹窗
            }else {
                label1.setText("正在监听" + textField_port.getText() + "端口");
                ip = textField_ip.getText();
                otherPort = Integer.parseInt(textField_port.getText());

                if (otherPort == 10002){
                    localPort = 10001;
                }
                else {
                    localPort = 10002;
                }

                new Receive().start();//启动监听线程
                System.out.println(localPort);
                System.out.println(otherPort);
                button_concern.setEnabled(false);//设置按钮不可再点击
            }

        }
    }

2.6.2、“清空”按钮

功能:实现聊天记录的清空

//监听事件
    @Override
    public void actionPerformed(ActionEvent e) {

        Object source = e.getSource();


        if (button_send.equals(source)){//发送
           ......
        }else if (button_clear.equals(source)){//清空
            textArea_history.setText("");
        }else if (button_concern.equals(source)){//确定
            ......
    }
}

2.6.3、“发送”按钮

功能:实现数据的发送

  • 绑定监听事件
//监听事件
    @Override
    public void actionPerformed(ActionEvent e) {

        Object source = e.getSource();


        if (button_send.equals(source)){//发送
            if (textArea_message.getText().equals("")){
                JOptionPane.showMessageDialog(this,"不可发送空白信息!");
            }else {
                send();
            }

        }else if (button_clear.equals(source)){//清空
            ......
        }else if (button_concern.equals(source)){//确定
			......
}
  • 数据的发送
    采用UDP协议传输数据
	public void init(){
        ......
        //节约空间,防止每次发送数据都会new一个对象
        try {
            socket = new DatagramSocket();
        } catch (SocketException e) {
            e.printStackTrace();
        }
    }
    
	//用于文本框内信息的发送
    private void sendMessage(byte[] data){
        System.out.println("消息发送成功");
        try {
            DatagramPacket packet = new DatagramPacket(data, data.length, InetAddress.getByName(ip), localPort);
            socket.send(packet);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //发送消息
    private void send(){
        message = textArea_message.getText();
        byte[] data = message.getBytes();
        sendMessage(data);
        String str = "我对" + ip + ":" + otherPort + "说:" + message + '\n';
        textArea_history.append(str);//添加进聊天记录框
        textArea_message.setText("");//清空输入信息框
    }

2.6.4、“接收”线程

功能:实现信息的同步发送与接收

//程序运行时需要同步接收与发送,因此应该使用多线程,new一个线程用于接收消息
    private class Receive extends Thread{
        @Override
        public void run() {
            System.out.println("监听正在运行");
            DatagramPacket packet = null;
            try {
                socket = new DatagramSocket(otherPort);
                System.out.println("监听" + otherPort);
                byte[] data = new byte[1024*4];
                packet = new DatagramPacket(data, data.length);
                while (true){
                    socket.receive(packet);
                    byte[] bytes = packet.getData();
                    String message = new String(bytes,0,bytes.length);
                    String str = ip + ":" + localPort + "对我说:" + message + '\n';
                    textArea_history.append(str);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }

2.7、启动程序

import javax.swing.*;

/**
 * 启动程序
 * @author TT
 * @create 2020-06-16-0:53
 */
public class UDPChat extends JFrame {

    public static void main(String[] args) {
        JFrame frame = new JFrame("聊天室GUI版");
        frame.add(new UDPChatFace());//注意次序,add方法在前面
        frame.setVisible(true);
        frame.setSize(800,600);
        frame.setResizable(false);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }
}

2.8、注意事项

  • 该程序设置的两个端口号分别是10001和10002,因此若一个客户端用了10001,则另外一个客户端就应该输入10002,否则将出错
  • 该程序的IP设置默认为获取本机IP,即"自己与自己聊天",若需两个电脑之间进行互动(同一局域网),则只要将在文本框输入的IP地址设置为发送和接收的地址即可

3、小技巧

3.1、获取本机IP地址

  • " win + R" 打开 “运行”
  • 输入"cmd" ,回车,打开 “命令提示符”
  • 输入ipconfig,回车
  • 其中"IPV4"地址就是本机IP地址荐
                                                        Java基于UDP的GUI界面简易聊天室课程实验(获取本机IP、IDEA同个程序运行两次设置方法)

3.2、IDEA同个程序运行两次设置方法

  • 点击菜单栏的"Run"选项
  • 选择"Edit Configurations"
  • 勾选√窗口右上角的“Allow parallel run",点击“OK”即可

4、总结(UDP的理解)

说说博主的一些关于UDP的小想法,适用于刚接触UDP协议的小白:

  • UDP协议,不管是发送还是接收,都得有一个socket、一个packet
  • socket可以理解成是一个“快递公司”,packet理解成是一个“包裹”,不管我们是"寄快递"还是"收快递",“货物”(数据)都是存放于"包裹"里面的。因此,若是要发数据,则必须先将数据存储在packet里面,然后通过"socket.send(packet)“的方法将"包裹"寄出去;同理,若是要接收数据,则必须先创建一个byte[]类型的变量,可以理解成“装载包裹的车”,"车"得足够大,才能把"包裹"通过"socket.receive(packet)"的方法收下来,接着再读取数据。

看完的你可以收藏点赞哦o( ̄▽ ̄)ブ!
转载麻烦告知并标明出处!

本文地址:https://blog.csdn.net/ttbro/article/details/106799011