`
hxdawxyhxdawxy
  • 浏览: 127301 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

UDP传输数据

 
阅读更多
DatagramSocket本身只是码头,不维护状态,不能产生IO流,它的唯一作用就是接收和发送数据报,Java使用DatagramPacket来代表数据报,DatagramSocket接收和发送的数据都是通过DatagramPacket对象完成的。
先看一下DatagramSocket的构造器:
DatagramSocket():创建一个DatagramSocket实例,并将该对象绑定到本机默认IP地址、本机所有可用端口中随机选择的某个端口。
DatagramSocket(int prot):创建一个DatagramSocket实例,并将该对象绑定到本机默认IP地址、指定端口。
DatagramSocket(int port, InetAddress laddr):创建一个DatagramSocket实例,并将该对象绑定到指定IP地址、指定端口。
通过上面三个构造器中任意一个构造器即可创建一个DatagramSocket实例,通常在创建服务器时,我们创建指定端口的 DatagramSocket实例——这样保证其他客户端可以将数据发送到该服务器。一旦得到了DatagramSocket实例之后,就可以通过如下两 个方法来接收和发送数据:
receive(DatagramPacket p):从该DatagramSocket中接收数据报。
send(DatagramPacket p):以该DatagramSocket对象向外发送数据报。
从上面两个方法可以看出,使用DatagramSocket发送数据报时,DatagramSocket并不知道将该数据报发送到哪里,而是由 DatagramPacket自身决定数据报的目的。就像码头并不知道每个集装箱的目的地,码头只是将这些集装箱发送出去,而集装箱本身包含了该集装箱的 目的地。
当Client/Server程序使用UDP协议时,实际上并没有明显的服务器和客户端,因为两方都需要先建立一个DatagramSocket对 象,用来接收或发送数据报,然后使用DatagramPacket对象作为传输数据的载体。通常固定IP、固定端口的DatagramSocket对象所 在的程序被称为服务器,因为该DatagramSocket可以主动接收客户端数据。
下面看一下DatagramPacket的构造器:
DatagramPacket(byte buf[],int length):以一个空数组来创建DatagramPacket对象,该对象的作用是接收DatagramSocket中的数据。
DatagramPacket(byte buf[], int length, InetAddress addr, int port):以一个包含数据的数组来创建DatagramPacket对象,创建该DatagramPacket时还指定了IP地址和端口——这就决定了 该数据报的目的。
DatagramPacket(byte[] buf, int offset, int length):以一个空数组来创建DatagramPacket对象,并指定接收到的数据放入buf数组中时从offset开始,最多放length个字节。
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port):创建一个用于发送的DatagramPacket对象,也多指定了一个offset参数。
在接收数据前,应该采用上面的第一个或第三个构造器生成一个DatagramPacket对象,给出接收数据的字节数组及其长度。然后调用 DatagramSocket 的方法receive()等待数据报的到来,receive()将一直等待(也就是说会阻塞调用该方法的线程),直到收到一个数据报为止。如下代码所示:
//创建接受数据的DatagramPacket对象
DatagramPacket packet=new DatagramPacket(buf, 256);
//接收数据
socket.receive(packet);



发送数据之前,调用第二个或第四个构造器创建DatagramPacket对象,此时的字节数组里存放了想发送的数据。除此之外,还要给出完整的目 的地址,包括IP地址和端口号。发送数据是通过DatagramSocket的方法send()实现的,send()根据数据报的目的地址来寻径以传递数 据报。如下代码所示:

//创建一个发送数据的DatagramPacket对象
DatagramPacket packet = new DatagramPacket(buf, length, address, port);
//发送数据报
socket.send(packet);


当我们使用DatagramPacket来接收数据时,会感觉DatagramPacket设计得过于烦琐。对于开发者而言,只关心该 DatagramPacket能放多少数据,而DatagramPacket是否采用字节数组来存储数据完全不想关心。但Java要求创建接收数据用的 DatagramPacket时,必须传入一个空的字节数组,该数组的长度决定了该DatagramPacket能放多少数据,这实际上暴露了 DatagramPacket的实现细节。接着DatagramPacket又提供了一个getData()方法,该方法又可以返回 DatagramPacket对象里封装的字节数组,该方法更显得有些多余:如果程序需要获取DatagramPacket里封装的字节数组,直接访问传 给 DatagramPacket构造器的字节数组实参即可,无须调用该方法。
当服务器(也可以客户端)接收到一个DatagramPacket对象后,如果想向该数据报的发送者“反馈”一些信息,但由于UDP是面向非连接 的,所以接收者并不知道每个数据报由谁发送过来,但程序可以调用DatagramPacket的如下三个方法来获取发送者的IP和端口:
InetAddress getAddress():返回某台机器的 IP 地址,当程序准备发送次数据报时,该方法返回此数据报的目标机器的IP地址;当程序刚刚接收到一个数据报时,该方法返回该数据报的发送主机的IP地址。
int getPort():返回某台机器的端口,当程序准备发送此数据报时,该方法返回此数据报的目标机器的端口;当程序刚刚接收到一个数据报时,该方法返回该数据报的发送主机的端口。
SocketAddress getSocketAddress():返回完整SocketAddress,通常由IP地址和端口组成。当程序准备发送此数据报时,该方法返回此数据报 的目标SocketAddress;当程序刚刚接收到一个数据报时,该方法返回该数据报是源SocketAddress。
上面getSocketAddress方法的返回值是一个SocketAddress对象,该对象实际上就是一个IP地址和一个端口号,也就是说 SocketAddress对象封装了一个InetAddress对象和一个代表端口的整数,所以使用SocketAddress对象可以同时代表IP地 址和端口。
下面程序使用DatagramSocket实现Server/Client结构的网络通信程序,本程序的服务器端使用循环1000次来读取DatagramSocket中的数据报,每当读到内容之后便向该数据报的发送者送回一条信息。服务器端代码如下:


程序清单:codes/17/17-4/UdpServer.java
public class UdpServer
{
public static final int PORT = 30000;
//定义每个数据报的最大大小为4K
private static final int DATA_LEN = 4096;
//定义该服务器使用的DatagramSocket
private DatagramSocket socket = null;
//定义接收网络数据的字节数组
byte[] inBuff = new byte[DATA_LEN];
//以指定字节数组创建准备接受数据的DatagramPacket对象
private DatagramPacket inPacket = 
new DatagramPacket(inBuff , inBuff.length);
//定义一个用于发送的DatagramPacket对象
private DatagramPacket outPacket;
//定义一个字符串数组,服务器发送该数组的的元素
String[] books = new String[]
{
"轻量级J2EE企业应用实战",
"基于J2EE的Ajax宝典",
"Struts2权威指南",
"ROR敏捷开发最佳实践"
};
public void init()throws IOException
{
try
{
//创建DatagramSocket对象
socket = new DatagramSocket(PORT);
//采用循环接受数据
for (int i = 0; i < 1000 ; i++ )
{
//读取Socket中的数据,读到的数据放在inPacket所封装的字节数组里。
socket.receive(inPacket);
//判断inPacket.getData()和inBuff是否是同一个数组
System.out.println(inBuff == inPacket.getData());
//将接收到的内容转成字符串后输出
System.out.println(new String(inBuff ,
0 , inPacket.getLength()));
//从字符串数组中取出一个元素作为发送的数据
byte[] sendData = books[i % 4].getBytes();
//以指定字节数组作为发送数据、以刚接受到的DatagramPacket的
//源SocketAddress作为目标SocketAddress创建DatagramPacket。
outPacket = new DatagramPacket(sendData ,
sendData.length , inPacket.getSocketAddress());
//发送数据
socket.send(outPacket); 
}
}
//使用finally块保证关闭资源
finally
{
if (socket != null)
{
socket.close();
}
}
}
public static void main(String[] args) 
throws IOException
{
new UdpServer().init();
}
}



上面程序中粗体字代码就是使用DatagramSocket发送、接收DatagramPacket的关键代码,该程序可以接受1000个客户端发送过来的数据。
程序客户端代码也与此类似,客户端采用循环不断地读取用户键盘输入,每当读到用户输入内容后就将该内容封装成DatagramPacket数据报, 再将该数据报发送出去;接着把DatagramSocket中的数据读入接收用的DatagramPacket中(实际上是读入该 DatagramPacket所封装的字节数组中)。客户端代码如下:


程序清单:codes/17/17-4/UdpClient.java
public class UdpClient
{
//定义发送数据报的目的地
public static final int DEST_PORT = 30000;
public static final String DEST_IP = "127.0.0.1";
//定义每个数据报的最大大小为4K
private static final int DATA_LEN = 4096;
//定义该客户端使用的DatagramSocket
private DatagramSocket socket = null;
//定义接收网络数据的字节数组
byte[] inBuff = new byte[DATA_LEN];
//以指定字节数组创建准备接受数据的DatagramPacket对象
private DatagramPacket inPacket = 
new DatagramPacket(inBuff , inBuff.length);
//定义一个用于发送的DatagramPacket对象
private DatagramPacket outPacket = null;
public void init()throws IOException
{
try
{
//创建一个客户端DatagramSocket,使用随机端口
socket = new DatagramSocket();
//初始化发送用的DatagramSocket,它包含一个长度为0的字节数组
outPacket = new DatagramPacket(new byte[0] , 0 ,
InetAddress.getByName(DEST_IP) , DEST_PORT);
//创建键盘输入流
Scanner scan = new Scanner(System.in);
//不断读取键盘输入
while(scan.hasNextLine())
{
//将键盘输入的一行字符串转换字节数组
byte[] buff = scan.nextLine().getBytes();
//设置发送用的DatagramPacket里的字节数据
outPacket.setData(buff);
//发送数据报
socket.send(outPacket);
//读取Socket中的数据,读到的数据放在inPacket所封装的字节数组里。
socket.receive(inPacket);
System.out.println(new String(inBuff , 0 , 
inPacket.getLength()));
}
}
//使用finally块保证关闭资源
finally
{
if (socket != null)
{
socket.close();
}
}
}
public static void main(String[] args) 
throws IOException
{
new UdpClient().init();
}
}


上面程序的粗体字代码同样也是通过DatagramSocket发送、接收DatagramPacket的关键代码,这些代码与服务器的代码基本相 似。而客户端与服务器端的唯一区别在于:服务器所在IP地址、端口是固定的,所以客户端可以直接将该数据报发送给服务器,而服务器则需要根据接收到的数据 报来决定将“反馈”数据报的目的地。
读者可能会发现,使用DatagramSocket进行网络通信时,服务器端无须、也无法保存每个客户端的状态,客户端把数据报发送到服务器后,完全有可能立即退出。但不管客户端是否退出,服务器无法知道客户端的状态。
当使用UDP协议时,如果想让一个客户端发送的聊天信息可被转发到其他所有客户端则比较困难,可以考虑在服务器使用Set来保存所有客户端信息,每 当接收到一个客户端的数据报之后,程序检查该数据报的源SocketAddress是否在Set集合中,如果不在就将该SocketAddress添加到 该Set集合中,但这样一来又涉及一个问题:可能有些客户端发送一个数据报之后永久性地退出了程序,但服务器端还将该客户端的SocketAddress 保存在Set集合中……总之,这种方式需要处理的问题比较多,编程比较烦琐。幸好Java为UDP协议提供了MulticastSocket类,通过该类 可以轻松实现多点广播。



--------------------------------------------------------------------------------------------------------------------------------------------------------------------
小例子:

package com.justsee.tcpip;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class UdpRecv {

	//先启动这个类,等待接受信息。
	public static void main(String[] args) throws IOException {
		System.out.println("等待接受");
		DatagramSocket datagramSocket = new DatagramSocket(8080);//指定接受信息的端口
		byte[] buf = new byte[1024];//指定最大接受信息的大小
		DatagramPacket datagramPacket = new DatagramPacket(buf, 1024);
		datagramSocket.receive(datagramPacket);//阻塞等待
		String string = new String(datagramPacket.getData(), 0,
				datagramPacket.getLength())
				+ "  from  "
				+ datagramPacket.getAddress().getHostAddress()
				+ ":" + datagramPacket.getPort();
		System.out.println(string);
		datagramSocket.close();
	}

}




package com.justsee.tcpip;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
public class UdpSend {
	//后启动发送类。
	public static void main(String[] args) throws IOException {
		System.out.println("发送");
		DatagramSocket datagramSocket = new DatagramSocket();
		String str = "我是中国人!";
		//因为是发送的中文,所以str.length()改为str.getBytes().length。
		//指定发送到的ip和端口
		DatagramPacket datagramPacket = new DatagramPacket(str.getBytes(),
				str.getBytes().length, InetAddress.getByName("172.30.31.53"),
				8080);
		datagramSocket.send(datagramPacket);
		datagramSocket.close();
	}

}
/*发送和接受都是以DatagramSocket为信息载体*/
分享到:
评论

相关推荐

    摄像头udp传输 摄像头udp传输

    摄像头udp传输摄像头udp传输摄像头udp传输摄像头udp传输摄像头udp传输摄像头udp传输摄像头udp传输摄像头udp传输摄像头udp传输摄像头udp传输摄像头udp传输摄像头udp传输摄像头udp传输摄像头udp传输摄像头udp传输...

    C语言UDP传输数据得实现DEMO

    C语言UDP传输数据得实现DEMO

    UDP传输数据,移动方块,GDI+,图形移动

    在“UDP传输数据,移动方块,GDI+,图形移动”这个实例中,开发者利用UDP协议来实现实时地传输图形对象——方块的位置信息。这个过程通常涉及到以下几个关键步骤: 1. **创建UDP套接字**:首先,客户端和服务器都...

    TCP/UDP 传输数据

    本篇将详细阐述TCP和UDP协议的工作原理、特性以及它们在数据传输中的实现。 TCP,即传输控制协议,是一种面向连接的、可靠的、基于字节流的传输层通信协议。它通过三次握手建立连接,并在连接建立后进行数据传输,...

    基于MFC的简单UDP传输数据,可传输中文以及英文

    而UDP(User Datagram Protocol)是一种无连接的、不可靠的传输层协议,常用于实时数据传输或者对数据完整性要求不高的场景。本示例将重点介绍如何利用MFC实现简单的UDP数据传输,尤其是处理中文和英文数据的发送与...

    UDP传输数据-按键触发STOP.rar_NB STM32_NB-IoT stm32_nb-iot_stm32 nb-iot_

    NB-IOT stm32开发板的参考资料,功能为UDP传输数据-按键触发STOP

    tsunami-udp 是一款专为网络加速诞生的小工具 用TCP进行传输控制、用UDP进行数据传输

    tsunami-udp是一款创新的网络加速工具,它将TCP和UDP协议结合使用,旨在提高数据传输的效率和性能...4. 通过UDP传输数据:实际的数据则通过创建的UDP通道进行传输,利用UDP的高效、无连接的特性,大幅提高了数据传输的速度。

    UDP传输例子 UDP源码 UDP UDP传输 UDP发送文件 UDP发送

    在UDP传输中,数据是以数据报的形式发送的,每个数据报包含完整的源地址和目标地址,这意味着数据可以在不需要建立连接的情况下直接发送。由于没有连接建立过程,UDP具有更低的延迟,但同时也意味着数据可能会丢失、...

    qt udp传输文件

    4. **TCP辅助传输**:在描述中提到了TCP传输数据,TCP是一种面向连接、可靠的传输协议,适用于传输小量关键数据,比如文件头信息、确认信息等。可以创建`QTcpSocket`进行TCP通信,确保文件传输的相关控制信息的可靠...

    udp.rar_UDP C++ 数据_UDP 传输_UDP 数据传输_UDP 文件 传输_udp文件传输

    2. **数据报与数据结构**:UDP数据传输基于数据报,每个数据报包含一个UDP头部和数据部分。在C++中,我们需要定义结构体来存储这些信息,如`sockaddr_in`用于表示IP地址和端口,`struct sockaddr`用于通用的地址结构...

    基于UDP的Java大数据传输

    UDP传输的优点是快捷,因为它是没有安全保证的。有一定的丢失率。而且,由于各包的传输路径不同,后发送的包可能先于先发送的包到达。所以,如果发送大量的数据,就需要进行检错。当然,还得保证快捷的传输。 我就是...

    UDP十六进制数据传输

    相较于TCP,UDP提供了一种轻量级的数据传输方式,适用于对实时性要求高但对数据完整性要求相对较低的场景,如在线游戏、视频通话和DNS查询等。 在“UDP十六进制数据传输”这个主题中,我们关注的是如何以16进制格式...

    android udp传输实例

    下面将详细探讨Android UDP传输的实现及其相关知识点。 首先,我们要了解在Android中如何创建UDP套接字。Android系统提供了`java.net.DatagramSocket`类来处理UDP通信。创建一个UDP套接字可以使用`DatagramSocket()...

    UDP客户端与服务器端传输数据

    基于linux,vi,C语言的UDP传输数据。客户端与服务器端口通过端口号传数据。

    基于c++的udp传输,传送超过10M的文件

    在IT行业中,网络通信是至关重要的一个领域,UDP(User Datagram Protocol)作为传输层协议之一,因其简单高效而被广泛应用于实时数据传输,如在线视频、音频通话等。本话题聚焦于如何使用C++实现基于UDP的大文件...

    UDP传输与接收数据.rar_IOT STM32_NB STM32_UDP传输与接收数据_UDP接收

    NB-IOT stm32开发板的参考资料 UDP传输与接收数据

    基于java的UDP数据传输

    【标题】基于Java的UDP数据传输 在计算机网络通信中,UDP(User Datagram Protocol,用户数据报协议)是一种无连接的、不可靠的传输层协议,它提供了比TCP(Transmission Control Protocol,传输控制协议)更快的...

    UDP传输图片文件并显示

    在UDP传输中,客户端和服务器需要通过socket编程实现数据交换。创建socket,绑定本地端口,然后使用sendto向服务器发送数据,使用recvfrom接收数据。服务器也需要创建socket,绑定监听端口,并使用recvfrom等待接收...

    udp传输通信工具

    该"udp传输通信工具"可能是用于帮助开发者或者用户实现基于UDP协议的数据交互。它可能包含以下功能: 1. 数据发送:用户可以输入或上传需要发送的数据,工具会将数据封装成UDP数据报并发送到指定的IP地址和端口号。...

    UDP协议传输数据Java简单实现

    实现UDP协议传输数据的基本步骤如下: 1. **创建DatagramSocket**:客户端和服务端都需要创建一个`DatagramSocket`实例,这将分配一个本地端口用于发送和接收数据报。例如: ```java DatagramSocket socket = new...

Global site tag (gtag.js) - Google Analytics