java建立UDP连接和建立TCP/IP连接一样简单,只用到了SocketAddress(绑定主机的IP地址和应用程序端口,包括自己的和发送地)、DatagramSocket(数据套接字,接收和发送数据包都靠它,同时在new该对象时需要try…catch,而SocketAddress则无需)、DatagramPacket(数据包对象,UDP数据都是一个包一个包发送的)这三个类。然后实现起来是非常简单的。首先是发送方new两个SocketAddress对象,一个参数写自己的机子,另一个写要发送的目标主机。然后把自己的SocketAddress对象传入DatagramSocket创建其对象,假设对象名为ds。再将要发送的数据连同目标主机的SocketAddress对象一起传入DatagramPacket创建其对象,设为dp。最后调用方法ds.send(dp);就OK了。这是发送方的,接收方差不多,实现起来没多大难度。不过众所周知,UDP有一个特点却是比不上TCP/IP的,那就是建立的连接不一定非常可靠,经常会出现丢包的情况,所以需要在发送过程中添加检测机制,而这也就大大加大了实现的难度。基本检测机制是:
发送方发送一个数据包,接收方接收后,发回一个应答包告诉发送方已收到消息,此应答包包含发送的消息的唯一序列号。关于这个序列号的唯一性设置我还不是很明白,所以在测试中就把第n条消息的n作为序列号了。若发送方在一定时间内(时间长短可自行设置)未收到应答包则重发消息。重发消息有两个原因:①接收方未收到,此时重发是应该的。②接收方收到消息但是发回的应答包丢失了,此时重发消息则重复了,所以在接收方还得添加一个机制:若收到的消息与以前发过的消息重复,则再次发送应答包。在这些机制下,能够初步的保证UDP传输的完整性。以下是实现代码:
发送端:
- import java.io.IOException;
- import java.net.DatagramPacket;
- import java.net.DatagramSocket;
- import java.net.InetSocketAddress;
- import java.net.SocketAddress;
- import java.util.ArrayList;
- import java.util.List;
- public class UDPServer {
- public UDPServer() {
- try {
- sa = new InetSocketAddress("127.0.0.1", 9999);
- ds = new DatagramSocket(sa);
- saa = new InetSocketAddress("127.0.0.1", 1234);
- String msg = "";
- startThread();
- new Thread() {
- public void run() {
- while (true) {
- recMsg();
- }
- }
- }.start();
- for (int i = 1;; i++) {
- msg = "第" + i + "条消息";
- Msg m = new Msg(msg, i);
- sendMsg(m);
- list.add(m);
- Thread.sleep(1000);
- }
- } catch (Exception e) {
- }
- }
- public void sendMsg(Msg m) {
- DatagramPacket dp;
- try {
- dp = new DatagramPacket(m.getmsg().getBytes(), m.getmsg()
- .getBytes().length, saa);
- ds.send(dp);
- m.setsendtime(System.currentTimeMillis());
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- public void recMsg() {
- byte[] buffer = new byte[20];
- DatagramPacket dpp = new DatagramPacket(buffer, buffer.length);
- try {
- ds.receive(dpp);
- } catch (IOException e) {
- e.printStackTrace();
- }
- String rec = new String(dpp.getData()).trim();
- int id = Integer.parseInt(rec.substring(4, rec.length() - 3));
- for (int i = 0; i < list.size(); i++) {
- if (id == list.get(i).getid()) {
- System.out.println("确认对方已收到第" + list.get(i).getid()
- + "条消息,从队列中除去");
- list.remove(i);
- }
- }
- }
- public void startThread() {
- new Thread() {
- public void run() {
- while (true) {
- // 如果list里面有元素
- if (list.size() > 1) {
- for (int i = 0; i < list.size(); i++) {
- if (System.currentTimeMillis()
- - list.get(i).getsendtime() > 3000
- && list.get(i).gettime() < 4) {
- sendMsg(list.get(i));
- System.out.println("重发第" + list.get(i).getid()
- + "条消息第" + list.get(i).gettime() + "次");
- if (list.get(i).gettime() == 3) {
- System.out.println("重发第"
- + list.get(i).getid()
- + "条消息已超过4次,丢弃包");// System.exit(0);
- list.remove(i);
- } else {
- list.get(i).settime(
- list.get(i).gettime() + 1);
- }
- }
- }
- }
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- }.start();
- }
- public static void main(String[] args) {
- new UDPServer();
- }
- class Msg {
- public Msg(String msg, int id) {
- this.msg = msg;
- this.id = id;
- }
- public void setid(int i) {
- id = i;
- }
- public int getid() {
- return id;
- }
- public void setmsg(String newmsg) {
- msg = newmsg;
- }
- public String getmsg() {
- return msg;
- }
- public void settime(int i) {
- time = i;
- }
- public int gettime() {
- return time;
- }
- public void setsendtime(long time) {
- lastsendtime = time;
- }
- public long getsendtime() {
- return lastsendtime;
- }
- private int id;
- private String msg;
- private int time;
- private long lastsendtime;
- }
- List<Msg> list = new ArrayList<Msg>();
- SocketAddress sa;
- DatagramSocket ds;
- SocketAddress saa;
- }
接收端:
- import java.awt.Dimension;
- import java.awt.FlowLayout;
- import java.awt.Font;
- import java.io.IOException;
- import java.net.DatagramPacket;
- import java.net.DatagramSocket;
- import java.net.InetSocketAddress;
- import java.net.SocketAddress;
- import java.util.ArrayList;
- import java.util.List;
- import javax.swing.JFrame;
- import javax.swing.JScrollPane;
- import javax.swing.JTextArea;
- import javax.swing.UIManager;
- public class UDPClient {
- JFrame f;
- JTextArea jta, jta2;
- SocketAddress sa;
- SocketAddress saa;
- DatagramSocket ds;
- List<Msg> list = new ArrayList<Msg>();
- public UDPClient() {
- try {
- UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
- } catch (Exception e) {
- }
- Font font = new Font("Dialog", Font.PLAIN, 12);
- f = new JFrame();
- jta = new JTextArea();
- jta.setFont(font);
- jta2 = new JTextArea();
- jta2.setFont(font);
- JScrollPane jsp = new JScrollPane(jta);
- JScrollPane jsp2 = new JScrollPane(jta2);
- jsp.setPreferredSize(new Dimension(500, 400));
- jsp2.setPreferredSize(new Dimension(300, 400));
- f.setLayout(new FlowLayout());
- f.add(jsp);
- f.add(jsp2);
- f.pack();
- f.setLocationRelativeTo(null);
- f.setDefaultCloseOperation(3);
- f.setVisible(true);
- sa = new InetSocketAddress("127.0.0.1", 1234);
- saa = new InetSocketAddress("127.0.0.1", 9999);
- new Thread() {
- public void run() {
- recMsg();
- }
- }.start();
- startThread();
- }
- public void recMsg() {
- try {
- ds = new DatagramSocket(sa);
- while (true) {
- byte[] buffer = new byte[20];
- DatagramPacket dpp = new DatagramPacket(buffer, buffer.length);
- jta.append("等待数据...\n");
- ds.receive(dpp);
- String rec = new String(dpp.getData()).trim();
- if (check(rec)) {
- jta.append(rec + "\n");
- int id = Integer
- .parseInt(rec.substring(1, rec.length() - 3));
- Msg m = new Msg(rec, id);
- list.add(m);
- send(m);
- }
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- public boolean check(String msg) {
- if (list.size() > 0) {
- for (int i = 0; i < list.size(); i++) {
- if (list.get(i).getmsg().equals("msg")) {
- send(list.get(i));
- return false;
- }
- }
- }
- return true;
- }
- public void send(Msg m) {
- String msg = "已收到第" + m.getid() + "条消息";
- try {
- DatagramPacket dp = new DatagramPacket(msg.getBytes(),
- msg.getBytes().length, saa);
- ds.send(dp);
- jta2.append(msg + "\n");
- m.setrectime(System.currentTimeMillis());
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- public void startThread() {
- new Thread() {
- public void run() {
- while (true) {
- if (list.size() > 0) {
- for (int i = 0; i < list.size(); i++) {
- if (System.currentTimeMillis()
- - list.get(i).getrectime() > 5000) {
- list.remove(i);
- jta2.append("确认已收到第" + list.get(i).getid()
- + "条消息,从队列中除去\n");
- }
- }
- }
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- }.start();
- }
- public static void main(String[] args) {
- new UDPClient();
- }
- class Msg {
- public Msg(String msg, int id) {
- this.msg = msg;
- this.id = id;
- }
- public void setid(int i) {
- id = i;
- }
- public int getid() {
- return id;
- }
- public void setmsg(String newmsg) {
- msg = newmsg;
- }
- public String getmsg() {
- return msg;
- }
- public void settime(int i) {
- time = i;
- }
- public int gettime() {
- return time;
- }
- public void setrectime(long time) {
- lastrectime = time;
- }
- public long getrectime() {
- return lastrectime;
- }
- private int id;
- private String msg;
- private int time;
- private long lastrectime;
- }
- }
运行结果如图所示: