UDP传输的实现与检测重发机制

 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传输的完整性。以下是实现代码:

 

发送端:

 

Java代码   收藏代码
  1. import java.io.IOException;  
  2. import java.net.DatagramPacket;  
  3. import java.net.DatagramSocket;  
  4. import java.net.InetSocketAddress;  
  5. import java.net.SocketAddress;  
  6. import java.util.ArrayList;  
  7. import java.util.List;  
  8.   
  9. public class UDPServer {  
  10.   
  11.     public UDPServer() {  
  12.         try {  
  13.             sa = new InetSocketAddress("127.0.0.1"9999);  
  14.             ds = new DatagramSocket(sa);  
  15.             saa = new InetSocketAddress("127.0.0.1"1234);  
  16.             String msg = "";  
  17.             startThread();  
  18.             new Thread() {  
  19.                 public void run() {  
  20.                     while (true) {  
  21.                         recMsg();  
  22.                     }  
  23.                 }  
  24.             }.start();  
  25.             for (int i = 1;; i++) {  
  26.                 msg = "第" + i + "条消息";  
  27.                 Msg m = new Msg(msg, i);  
  28.                 sendMsg(m);  
  29.                 list.add(m);  
  30.                 Thread.sleep(1000);  
  31.             }  
  32.         } catch (Exception e) {  
  33.         }  
  34.     }  
  35.   
  36.     public void sendMsg(Msg m) {  
  37.         DatagramPacket dp;  
  38.         try {  
  39.             dp = new DatagramPacket(m.getmsg().getBytes(), m.getmsg()  
  40.                     .getBytes().length, saa);  
  41.             ds.send(dp);  
  42.             m.setsendtime(System.currentTimeMillis());  
  43.         } catch (IOException e) {  
  44.             e.printStackTrace();  
  45.         }  
  46.     }  
  47.   
  48.     public void recMsg() {  
  49.         byte[] buffer = new byte[20];  
  50.         DatagramPacket dpp = new DatagramPacket(buffer, buffer.length);  
  51.         try {  
  52.             ds.receive(dpp);  
  53.         } catch (IOException e) {  
  54.             e.printStackTrace();  
  55.         }  
  56.         String rec = new String(dpp.getData()).trim();  
  57.         int id = Integer.parseInt(rec.substring(4, rec.length() - 3));  
  58.         for (int i = 0; i < list.size(); i++) {  
  59.             if (id == list.get(i).getid()) {  
  60.                 System.out.println("确认对方已收到第" + list.get(i).getid()  
  61.                         + "条消息,从队列中除去");  
  62.                 list.remove(i);  
  63.             }  
  64.         }  
  65.     }  
  66.   
  67.     public void startThread() {  
  68.         new Thread() {  
  69.             public void run() {  
  70.                 while (true) {  
  71.                     // 如果list里面有元素  
  72.                     if (list.size() > 1) {  
  73.                         for (int i = 0; i < list.size(); i++) {  
  74.                             if (System.currentTimeMillis()  
  75.                                     - list.get(i).getsendtime() > 3000  
  76.                                     && list.get(i).gettime() < 4) {  
  77.                                 sendMsg(list.get(i));  
  78.                                 System.out.println("重发第" + list.get(i).getid()  
  79.                                         + "条消息第" + list.get(i).gettime() + "次");  
  80.                                 if (list.get(i).gettime() == 3) {  
  81.                                     System.out.println("重发第"  
  82.                                             + list.get(i).getid()  
  83.                                             + "条消息已超过4次,丢弃包");// System.exit(0);  
  84.                                     list.remove(i);  
  85.                                 } else {  
  86.                                     list.get(i).settime(  
  87.                                             list.get(i).gettime() + 1);  
  88.                                 }  
  89.                             }  
  90.                         }  
  91.                     }  
  92.                     try {  
  93.                         Thread.sleep(1000);  
  94.                     } catch (InterruptedException e) {  
  95.                         e.printStackTrace();  
  96.                     }  
  97.                 }  
  98.             }  
  99.         }.start();  
  100.     }  
  101.   
  102.     public static void main(String[] args) {  
  103.         new UDPServer();  
  104.     }  
  105.   
  106.     class Msg {  
  107.         public Msg(String msg, int id) {  
  108.             this.msg = msg;  
  109.             this.id = id;  
  110.         }  
  111.   
  112.         public void setid(int i) {  
  113.             id = i;  
  114.         }  
  115.   
  116.         public int getid() {  
  117.             return id;  
  118.         }  
  119.   
  120.         public void setmsg(String newmsg) {  
  121.             msg = newmsg;  
  122.         }  
  123.   
  124.         public String getmsg() {  
  125.             return msg;  
  126.         }  
  127.   
  128.         public void settime(int i) {  
  129.             time = i;  
  130.         }  
  131.   
  132.         public int gettime() {  
  133.             return time;  
  134.         }  
  135.   
  136.         public void setsendtime(long time) {  
  137.             lastsendtime = time;  
  138.         }  
  139.   
  140.         public long getsendtime() {  
  141.             return lastsendtime;  
  142.         }  
  143.   
  144.         private int id;  
  145.         private String msg;  
  146.         private int time;  
  147.         private long lastsendtime;  
  148.     }  
  149.   
  150.     List<Msg> list = new ArrayList<Msg>();  
  151.     SocketAddress sa;  
  152.     DatagramSocket ds;  
  153.     SocketAddress saa;  
  154.   
  155. }  

 

 

接收端:

Java代码   收藏代码
  1. import java.awt.Dimension;  
  2. import java.awt.FlowLayout;  
  3. import java.awt.Font;  
  4. import java.io.IOException;  
  5. import java.net.DatagramPacket;  
  6. import java.net.DatagramSocket;  
  7. import java.net.InetSocketAddress;  
  8. import java.net.SocketAddress;  
  9. import java.util.ArrayList;  
  10. import java.util.List;  
  11.   
  12. import javax.swing.JFrame;  
  13. import javax.swing.JScrollPane;  
  14. import javax.swing.JTextArea;  
  15. import javax.swing.UIManager;  
  16.   
  17. public class UDPClient {  
  18.   
  19.     JFrame f;  
  20.     JTextArea jta, jta2;  
  21.     SocketAddress sa;  
  22.     SocketAddress saa;  
  23.     DatagramSocket ds;  
  24.     List<Msg> list = new ArrayList<Msg>();  
  25.   
  26.     public UDPClient() {  
  27.         try {  
  28.             UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());  
  29.         } catch (Exception e) {  
  30.         }  
  31.         Font font = new Font("Dialog", Font.PLAIN, 12);  
  32.         f = new JFrame();  
  33.         jta = new JTextArea();  
  34.         jta.setFont(font);  
  35.         jta2 = new JTextArea();  
  36.         jta2.setFont(font);  
  37.         JScrollPane jsp = new JScrollPane(jta);  
  38.         JScrollPane jsp2 = new JScrollPane(jta2);  
  39.         jsp.setPreferredSize(new Dimension(500400));  
  40.         jsp2.setPreferredSize(new Dimension(300400));  
  41.         f.setLayout(new FlowLayout());  
  42.         f.add(jsp);  
  43.         f.add(jsp2);  
  44.         f.pack();  
  45.         f.setLocationRelativeTo(null);  
  46.         f.setDefaultCloseOperation(3);  
  47.         f.setVisible(true);  
  48.         sa = new InetSocketAddress("127.0.0.1"1234);  
  49.         saa = new InetSocketAddress("127.0.0.1"9999);  
  50.         new Thread() {  
  51.             public void run() {  
  52.                 recMsg();  
  53.             }  
  54.         }.start();  
  55.         startThread();  
  56.     }  
  57.   
  58.     public void recMsg() {  
  59.         try {  
  60.             ds = new DatagramSocket(sa);  
  61.             while (true) {  
  62.                 byte[] buffer = new byte[20];  
  63.                 DatagramPacket dpp = new DatagramPacket(buffer, buffer.length);  
  64.                 jta.append("等待数据...\n");  
  65.                 ds.receive(dpp);  
  66.                 String rec = new String(dpp.getData()).trim();  
  67.                 if (check(rec)) {  
  68.                     jta.append(rec + "\n");  
  69.                     int id = Integer  
  70.                             .parseInt(rec.substring(1, rec.length() - 3));  
  71.                     Msg m = new Msg(rec, id);  
  72.                     list.add(m);  
  73.                     send(m);  
  74.                 }  
  75.             }  
  76.         } catch (IOException e) {  
  77.             e.printStackTrace();  
  78.         }  
  79.     }  
  80.   
  81.     public boolean check(String msg) {  
  82.         if (list.size() > 0) {  
  83.             for (int i = 0; i < list.size(); i++) {  
  84.                 if (list.get(i).getmsg().equals("msg")) {  
  85.                     send(list.get(i));  
  86.                     return false;  
  87.                 }  
  88.             }  
  89.         }  
  90.         return true;  
  91.     }  
  92.   
  93.     public void send(Msg m) {  
  94.         String msg = "已收到第" + m.getid() + "条消息";  
  95.         try {  
  96.             DatagramPacket dp = new DatagramPacket(msg.getBytes(),  
  97.                     msg.getBytes().length, saa);  
  98.             ds.send(dp);  
  99.             jta2.append(msg + "\n");  
  100.             m.setrectime(System.currentTimeMillis());  
  101.         } catch (IOException e) {  
  102.             e.printStackTrace();  
  103.         }  
  104.     }  
  105.   
  106.     public void startThread() {  
  107.         new Thread() {  
  108.             public void run() {  
  109.                 while (true) {  
  110.                     if (list.size() > 0) {  
  111.                         for (int i = 0; i < list.size(); i++) {  
  112.                             if (System.currentTimeMillis()  
  113.                                     - list.get(i).getrectime() > 5000) {  
  114.                                 list.remove(i);  
  115.                                 jta2.append("确认已收到第" + list.get(i).getid()  
  116.                                         + "条消息,从队列中除去\n");  
  117.                             }  
  118.                         }  
  119.                     }  
  120.                     try {  
  121.                         Thread.sleep(1000);  
  122.                     } catch (InterruptedException e) {  
  123.                         e.printStackTrace();  
  124.                     }  
  125.                 }  
  126.             }  
  127.         }.start();  
  128.     }  
  129.   
  130.     public static void main(String[] args) {  
  131.         new UDPClient();  
  132.     }  
  133.   
  134.     class Msg {  
  135.         public Msg(String msg, int id) {  
  136.             this.msg = msg;  
  137.             this.id = id;  
  138.         }  
  139.   
  140.         public void setid(int i) {  
  141.             id = i;  
  142.         }  
  143.   
  144.         public int getid() {  
  145.             return id;  
  146.         }  
  147.   
  148.         public void setmsg(String newmsg) {  
  149.             msg = newmsg;  
  150.         }  
  151.   
  152.         public String getmsg() {  
  153.             return msg;  
  154.         }  
  155.   
  156.         public void settime(int i) {  
  157.             time = i;  
  158.         }  
  159.   
  160.         public int gettime() {  
  161.             return time;  
  162.         }  
  163.   
  164.         public void setrectime(long time) {  
  165.             lastrectime = time;  
  166.         }  
  167.   
  168.         public long getrectime() {  
  169.             return lastrectime;  
  170.         }  
  171.   
  172.         private int id;  
  173.         private String msg;  
  174.         private int time;  
  175.         private long lastrectime;  
  176.     }  
  177.   
  178. }  

运行结果如图所示:

 

 

 


  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值