DatagramSocket本身只是码头,不维护状态,不能产生I/O流,其唯一的功能是接收和发送数据报。Java语言使用DatagramPacket代表数据报,DatagramSocket的接收和发送数据功能都是通过DatagramPacket对象实现的。
在DatagramSocket中有如下三个构造器。
□DatagramSocket():负责创建一个DatagramSocket实例,并将该对象绑定到本机默认的IP地址、本机所有可用端口中随机选择的某个端口。
□DatagramSocket(int prot):负责创建一个DatagramSocket实例,并将该对象绑定到本机默认的IP地址、指定的端口。
□DatagramSocket(int port,InetAddress laddr):负责创建一个DatagramSocket实例,并将该对象绑定到指定的IP地址、指定的端口。
在Java程序中,通过上述任意一个构造器即可创建一个DatagramSocket实例。在创建服务器时必须创建指定端口的DatagramSocket实例,目的是保证其他客户端可以将数据发送到该服务器。一旦得到了DatagramSocket实例,就可以通过下面的两个方法接收和发送数据。
□receive(DatagramPacket p):从该DatagramSocket中接收数据报。
□send(DatagramPacket p):以该DatagramSocket对象向外发送数据报。
在使用DatagramSocket发送数据报时,DatagramSocket并不知道将该数据报发送到何处,而是由DatagramPacket决定数据报的去处。就像码头并不知道每个集装箱的目的地,码头只是将这些集装箱发送出去,而集装箱本身包含了该集装箱的目的地。
当C/S程序使用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参数。(www.xing528.com)
在接收数据前,应该采用上面的第一个或第三个构造器生成一个DatagramPacket对象,给出接收数据的字节数组及其长度。然后调用DatagramSocket中的receive()方法等待数据报的到来,此方法将一直等待(阻塞调用该方法的线程),直到收到一个数据报为止。例如下面的代码。
在发送数据之前,调用第二个或第四个构造器创建DatagramPacket对象,此时的字节数组里存放了想发送的数据。除此之外,还要给出完整的目的地址,包括IP地址和端口号。发送数据是通过DatagramSocket的方法send()实现的,方法send()根据数据报的目的地址来传递数据报。例如下面的代码。
DatagramPacket为我们提供了getData()方法,此方法可以返回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地址和端口。
例如下面是一段实现UDP的服务端代码。
源码路径:daima\5\tcpudp\src\UdpServer.java
上述代码使用DatagramSocket实现了C/S结构的网络通信程序,其中服务端使用1000次循环来读取DatagramSocket中的数据报,每当读到内容之后便向该数据报的发送者送回一条信息。
接下看客户端的实现代码,客户端代码与服务端类似,也是采用循环,不断地读取用户键盘输入,每当读到用户输入内容后就将该内容封装成DatagramPacket数据报,再将该数据报发送出去。然后把DatagramSocket中的数据读入接收用的DatagramPacket中(实际上是读入该DatagramPacket所封装的字节数组中)。例如下面是一段实现UDP的客户端代码。
源码路径:daima\5\tcpudp\src\UdpClient.java
上述代码通过DatagramSocket实现了发送并接收DatagramPacket的功能,具体实现与服务器的实现代码基本相似。而客户端与服务端的唯一区别是服务器所在IP地址和端口是固定的,所以客户端可以直接将该数据报发送给服务器,而服务器需要根据接收到的数据报决定“反馈”数据报的目的地。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。