荐 Java基于UDP的GUI界面简易聊天室课程实验(获取本机IP、IDEA同个程序运行两次设置方法)
程序员文章站
2022-03-11 15:13:13
项目阐述基于UDP协议编写一个GUI界面的简易聊天室UDP通信协议优点:传输速度快,安全性高原因:不同于TCP的三次握手协议,UDP是一个无状态的传输协议,因此传输数据非常快;由于没有TCP的确认机制、三次握手机制等多种机制,因此相对较为安全,但并不是绝对安全。缺点:不可靠,只负责发送,不负责一定“送”到适用于对数据传输速度要求较高,质量不高的场合,如:视频、通讯、游戏等......
基于UDP的GUI简易聊天室
1、效果图
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地址
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
上一篇: 刑捕头经典台词语录