Java实现UDP网络通信的程序设计实例
学到java网络通信这一章,简单记录一下两种常见的通信协议:
- TCP通信协议,类似两个人打电话,提供两台计算机之间的数据互传,传播的数据准确可靠;
- UDP通信协议,是一种无连接的通信协议,类似发广播,不保障数据能可靠传输,适用于数据准确性要求不高,但对传输速度和时效性要求比较高的网站。
服务器端程序
package Number;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Sender extends Thread {
Date date = new Date();
SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
String weather = "节目预报:今晚八点有大型晚会,注意收听收看";
InetAddress inetAddress;
int port = 9898;
MulticastSocket socket;
public Sender() {
try {
inetAddress = InetAddress.getByName("224.255.10.0");
socket = new MulticastSocket(port);
socket.joinGroup(inetAddress);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
super.run();
while (true) {
DatagramPacket packet;
String message = "[" + format.format(date) + "]" + weather;
byte[] data = message.getBytes();
packet = new DatagramPacket(data, data.length, inetAddress, port);
System.out.println(message);
try {
socket.send(packet);
Thread.sleep(1000);
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Sender send = new Sender();
send.start();
}
}
客户端接收广播程序
import com.sun.javafx.logging.JFRInputEvent;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.*;
public class Receive extends JFrame implements Runnable, ActionListener {
JButton ince = new JButton("开始接收");
JButton stop = new JButton("停止接收");
JTextArea inceAr = new JTextArea(10, 10);
JTextArea inced = new JTextArea(10, 10);
Thread thread;
boolean getMessage = true;
InetAddress inetAddress;
int port = 9898;
MulticastSocket socket;
public Receive() {
super("广播数据报");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
inceAr.setForeground(Color.blue);
JPanel north = new JPanel();
north.add(ince);
north.add(stop);
ince.addActionListener(this);
stop.addActionListener(this);
add(north, BorderLayout.NORTH);
JPanel center = new JPanel();
center.setLayout(new GridLayout(1, 2));
center.add(inceAr);
final JScrollPane js = new JScrollPane();
center.add(js);
js.setViewportView(inced);
add(center, BorderLayout.CENTER);
thread = new Thread(this);
validate();
setBounds(100, 50, 800, 380);
try {
inetAddress = InetAddress.getByName("224.255.10.0");
socket = new MulticastSocket(port);
socket.joinGroup(inetAddress);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
while (getMessage) {
DatagramPacket packet;
byte[] data = new byte[1024];
packet = new DatagramPacket(data, data.length, inetAddress, port);
try {
socket.receive(packet);
String message = new String(packet.getData(), 0, packet.getLength());
inceAr.setText("正在接收的广播:\n" + message);
inced.append(message + "\n");
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == ince) {
ince.setBackground(Color.red);
stop.setBackground(Color.yellow);
if (!thread.isAlive()) {
thread = new Thread(this);
getMessage = true;
}
thread.start();
}
if (e.getSource() == stop) {
ince.setBackground(Color.yellow);
stop.setBackground(Color.red);
getMessage = false;
}
}
public static void main(String[] args) {
Receive receive = new Receive();
receive.setVisible(true);
}
}
先记录swing中几个容易忘记的知识点:
-
center.add(inceAr);
final JScrollPane js = new JScrollPane();
center.add(js);
js.setViewportView(inced);
add(center, BorderLayout.CENTER);
这里是swing的基础,就是滚动条到底该怎么设置,inced是一个文本域,它接收的信息很多,可能会超出文本域的范围,所以有必要加入一个滚动条,首先是新建了一个滚动条final JScrollPane js = new JScrollPane(); 至于为要强调是常量,我还没搞明白,待以后再去深挖。在布局中先添加这个滚动条,js.setViewportView(inced); 这行代码挺重要,意思是滚动条中设置视口,并在括号内设置视图为inced,也可以使用下面的代码: final JScrollPane js = new JScrollPane(inced);
即创建滚动条的时候,就把文本域inced添加到其中,之前有一篇博客提到过,但还是忘了,所以这是一个很容易忘记的知识点。 -
public class Receive extends JFrame implements Runnable, ActionListener 在创建类的时候,这个类就继承自JFrame类,然后实现了Runnable和ActionListener这两个接口,Runnable要实现的话,需要重写run方法;以往在swing中,给按钮设置监听方法时,都是在实例化按钮时直接给按钮重写监听方法(如下面的代码),采用实现接口的方式来写监听还没接触过,因此要记录一下,说明有这种写法。 private JButton getCloseButton(){
closeButton = new JButton("读取文件");
closeButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
File file = new File("text.txt");
try {
FileReader reader = new FileReader(file);
char chars[] = new char[1024];
int len = reader.read(chars);
jTextArea.setText(new String(chars, 0, len));
reader.close();
} catch (FileNotFoundException fileNotFoundException) {
fileNotFoundException.printStackTrace();
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
});
return closeButton;
-
如何判断哪个按钮被点击了呢,if (e.getSource() == ince) 就是这行代码,通过e.getSource()方法来判断被点击的按钮,来写不同按钮点击后应实现的功能,这有个好处,就是不用像上面一样,每次创建一个按钮,就来给这个按钮添加一个监听方法,这也是要重点学习的方法。
UDP网络通信的理解
- 首先,要搞清楚DatagramPacket类,这个类用来表示数据包,看看它的参数:
DatagramPacket(data, data.length, inetAddress, port);
- 第一个参数data是需要传输的数据
- 第二个单数是传输数据的长度
- 第三个参数是地址
- 第四个参数是端口
类似于寄快递,要寄的东西,东西有多重,收件人地址和收件人
-
然后,要搞明白套接字socket,它实例化的地方在构造方法这里: socket = new MulticastSocket(port);
MulticastSocket可以将数据报以广播的方式发送到多个客户端,也就是说,这句代码实现了多点广播套接字。只需要指定端口,然后用joinGroup方法将广播组加入即可。 -
接收类中,用到了一个receive方法来接收数据包。
示例结果
先启动服务端程序Sender发送数据:
然后启动客户端程序:
|