`
zhuyifeng
  • 浏览: 44931 次
  • 性别: Icon_minigender_1
社区版块
存档分类
最新评论

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

 

发送端:

 

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;
	}

}

 

 

运行结果如图所示:

 

 

 

  • 大小: 95.9 KB
0
1
分享到:
评论

相关推荐

    udp文件传输-有源码

    本文将深入探讨如何在UDP的基础上,通过添加验证和重发机制,实现稳定且高效的文件传输。 #### UDP协议特性与局限 UDP协议设计的初衷是为了提供一种轻量级、快速的通信方式,它不进行三次握手建立连接,也不进行...

    UDP实现可靠文件传输.doc

    总结来说,实现UDP上的可靠文件传输,关键在于设计合适的错误检测和恢复策略,如使用滑动窗口协议配合重传机制。通过这种方式,即使UDP本身的不可靠特性,也可以通过软件层面的手段来弥补,达到类似TCP的可靠传输...

    java udp视频传输

    可能的策略包括重发机制、错误检测码如CRC(Cyclic Redundancy Check)等。 5. **视频编码与解码**:视频数据通常是经过编码的,如H.264、VP9等,发送前需要将其编码为字节流。接收端收到字节流后,需解码恢复成...

    bcb UDP传文件(使用TNMUDP控件)

    实现一个基于UDP的文件传输系统需要考虑重发机制,因为UDP协议本身并不提供任何内置的重传功能。通过TNMUDP控件,我们可以创建一个简单的客户端-服务器模型,允许文件在两者之间可靠地传输。首先,我们需要在服务器...

    UDP实现可靠的文件传输

    3. **数据包重发机制** - 当发送端在规定时间内没有收到接收端的确认时,重新发送相应的数据包。 - 使用互斥锁来确保对缓冲队列的操作是线程安全的。 #### 六、总结 通过上述介绍,我们可以看出,虽然UDP自身不...

    UDP简单文件传输

    与TCP相比,UDP提供了较少的错误检测和流量控制机制,因此它更注重速度和效率,常用于实时应用如在线视频、语音通话以及简单的文件传输。 在这个“UDP简单文件传输”项目中,开发人员利用MFC(Microsoft Foundation...

    udt源码 udp可靠性传输

    总的来说,UDT通过在UDP基础上添加额外的机制,实现了高效且可靠的传输服务,是应对大数据传输挑战的一种有效解决方案。通过阅读"UDT2"的源代码,我们可以更深入地理解其实现细节,为自己的项目或研究提供参考。

    C#UDP通讯组件,支持拆包组包,丢包重发

    为了确保数据的完整性,此组件实现了检测丢包并进行重发的功能。通常,这会通过序列号和超时重传策略来实现。 3. **简单易用的API**:描述中提到,该组件的调用方式简单,这意味着开发者可以快速集成到自己的应用中...

    VS UDP传输文件例子

    3. **错误检测与重传**:由于UDP的不可靠性,我们需要引入一种机制来检测丢失的数据包,并要求发送方重新发送。可以使用序列号和确认机制,当接收端接收到数据包后,发送确认信息,如果发送方在一定时间内未收到确认...

    c#中关于udp实现可靠地传输(数据包的分组发送)

    总的来说,C#中通过UDP实现可靠传输需要综合运用多种技术,包括序列号、确认机制、重传超时、滑动窗口、数据校验和流量控制。这些技术能够帮助我们在保留UDP优点的同时,克服其天生的不可靠性,实现类似TCP的传输...

    linux 下的UDP 自定义协议 实现文件传输

    1. 设置超时重发机制:如果在一定时间内未收到确认,客户端可以重发数据报。 2. 序列号:在协议头中加入序列号,便于检测乱序的数据报。 3. 滑动窗口:通过限制同时未确认的数据报数量,可以控制网络拥塞并提高效率...

    序列号和TCP/UDP重发协议课件

    在计算机网络中,序列号和TCP/UDP重发协议是确保数据可靠传输的关键机制。滑动窗口协议是一种流量控制策略,用于管理数据在网络中的发送速率,以防止数据包的丢失、重复或乱序。 滑动窗口协议的工作原理是基于两个...

    基于UDP通信协议的设计与实现

    ### 基于UDP通信协议的设计与实现 #### 一、引言 随着信息技术的快速发展,网络通信成为了现代社会不可或缺的一部分。TCP/IP协议族作为互联网通信的基础,其成员之一的用户数据报协议(UDP)因其简单高效的特点,...

    c#udp通讯类文件传输

    然而,在文件传输这种对数据完整性和顺序有较高要求的场景下,单纯使用UDP可能不够,我们需要自行实现一些机制来增强其可靠性。 在C#中,我们可以使用`System.Net.Sockets.UdpClient`类来操作UDP套接字。这个类提供...

    C# UDP 文件发送

    2. **丢包重发机制**:由于UDP的不可靠性,我们需要自行实现丢包检测和重发策略。可以设置一个超时时间,如果在该时间内未收到接收方的确认信息(例如,通过TCP或另一条UDP通道返回一个确认消息),则重新发送数据包...

    基于UDP 通信协议的设计与实现

    ### 基于UDP通信协议的设计与实现 #### 一、引言 随着信息技术的快速发展,网络通信成为了现代社会不可或缺的一部分。TCP/IP协议族作为互联网通信的基础,在数据传输方面发挥着核心作用。其中,用户数据报协议...

    c语言UDP传输系统源码.zip

    【C语言UDP传输系统源码】是一个用于学习和参考的游戏源码项目,它涉及了网络编程中的基础概念,特别是用户数据报协议(UDP)的应用。UDP是互联网协议族中的一个无连接、不可靠的传输协议,它在实现时通常比TCP...

    基于udp的局域网聊天及文件传输程序

    标题中的“基于udp的局域网聊天及文件传输程序”是指使用UDP(User Datagram Protocol)协议在局域网内实现的通信应用。UDP是一种无连接的、不可靠的传输层协议,它不保证数据包的顺序和完整性,但因为其简单高效的...

    c#UDP组包分包接收发送

    在这个场景中,我们关注的是使用C#实现UDP(用户数据报协议)的组包、分包、接收和发送功能,以及数据包的重发机制。 首先,UDP是一种无连接的传输层协议,它不保证数据的顺序和可靠性,但相比TCP,其速度更快,...

    UDP.rar_C# UDP 服务器_UDP_UDP服务器_数据传输

    - **错误检测**:由于UDP的不可靠性,需要自定义错误检测机制,比如添加校验和。 - **数据包排序**:如果数据需要按顺序处理,服务器端可能需要维护一个队列来重新排序收到的数据包。 - **超时重发**:对于关键数据...

Global site tag (gtag.js) - Google Analytics