Java网络—基于UDP的网络程序设计
UDP(User Datagram Protocol)
java.net.DatagramSocket
①首先解释一下基于UDP的网络传输协议的传输方式:
我知道在基于TCP的传输协议是一种可靠的、建立起通讯通道的传输协议;这种传输协议要求在客户端和服务器端要通信就必须首先建立起通讯通道,一旦建立起这个通道的话,双方之间所有的交流信息都会全部的、按顺序的进行传送, 而且注意这样一个问题:一旦accept链接成功的话,那么即使双方没有进行数据的交互,这个链接通道也不会中断,而是一直保持着联通的状态;
②虽然上面的TCP传输方式非常的稳定,但是在下面的这些实际情况下使用TCP传输协议显然是不合适的:
(1)TCP传输协议中,只有当服务器端和客户端建立起联系之后,才能够将才能够将想要传输的数据在网络中进行传输,但是比如说我们现在有一个类似于广播程序,这个广播一直都在网络中进行实时的数据传输,但是这可以在没有客户端(或者服务器端)链接的情况下进行,一旦有客户端链接进来的话,客户端就能够收到在当下传输到网络中的广播数据,但是之前广播的数据就不会被刚刚连接进来的客户端收到,但这正是广播这种实时性传输的特点;这样的“广播”程序显然是不能够通过TCP传输协议来进行的,需要用UDP来实现
(2)有时,我们并不想像TCP那样,一直在客户端和服务器端都存在这通道的链接,如果存在非常多的这种没有必要的链接的话,就会非常的耗费资源和时间,影响数据传输的效率;比如说QQ中,有100个好友处在在线状态,但是我们没有必要和所有的这些在线的好友全部建立连接,只有我们想和某位好友进行通话时才会链接;所以在这个实例中如果用TCP来实现“在线状态”的传输 ,就非常的不好,因为有100 个在线,TCP服务器端要知道谁在线就必须要和谁建立连接,所以要建立100个链接,但是这是没有必要的,因为你并不需要和他们通话;解决的方法就是:使用UDP来传输这种“在线状态”,而当我们在和某人真正的聊天时,在使用TCP;在以后的实例中我们会讲解QQ的创建方法的
③下面就来介绍一下什么是UDP
UDP比TCP具有更加快的传输效率,但是并不可靠。
UDP发送的数据单元称为UDP数据报,当网络传输UDP数据报时,无法保证数据一定到达指定的目的地,也无法保证各个数据单元能够按照发送的顺序到达目的地,也可能在传输的过程中干脆就丢了;但是UDP有一个非常好的特点那就是它不要求通信的双方建立起一个可靠的网络通道,只是负责接收数据报和发送数据报,一旦有符合条件的数据报到达自己的网络端口,就接收它,否则就等待符合条件的数据报,这就大大的提高了传输的效率,在有些场合中使用UDP是非常的合适的
《》下面正式的介绍基于UDP网络传输协议的程序设计
1、如果要想使用UDP进行数据的收接和数据的发送,就要创建 数据报套接字(Datagram Socket) ;使用UDP进行传输的数据都要将数据封装在
数据报包(Datagram Package)中
在客户端和服务器端的程序设计几乎是一样的
2、数据报套接字实例对象的创建
创建数据报套接字的实例对象通常通过使用java.net.DatagramSocket类的构造方法:
①public DatagramSocket (int port)
throws SocketException
②public DatagramSocket ( )
throws SocketException
注意:
(1)在服务器端创建套接字对象使用带有端口号参数的构造方法;而在客户端一般使用不带有任何参数的构造方法;
这是由于:每台计算机的每个指定的端口号最都只能够分配给一个数据报套接字对象;因此,如果服务器和客户端位于同一台电脑上,那么他们就不能够采用相同的端口号创建数据报套接字对象;
(2)而不带参数的构造方法的机制是:让计算机自动为客户端的数据报套接字对象查找并配置当前可用的端口号;
但是,你可能会想,那么客户端的的套接字对象既然没有指定目标服务器端的端口号,又怎么能够将发送的数据传输到想要传输到的服务器呢?事实上,这个问题根本就不是个问题,因为正如下面将要介绍的,当我们在创建发送数据报包时,会指定目标服务器的IP和端口号;
(3)那么现在又有一个问题,那就是既然在客户端使用的是没有任何参数的套接字构造方法,那么我们就不会知道客户端使用的端口号具体是什么,那么服务器端在创建发送数据报包时,又该如何指定向哪个服务器发送数据呢?这实际上也不用担心,因为在服务器端接收到的由客户端发送过来的数据包中已经自动将客户端的IP和端口号封装在其中了,所以可以从中获得想要的信息;这也就说明了一个问题,那就是一般来说,基于UDP的通信应该先由客户端向服务器端发送数据报包,之后才能够进行交互通信(当然我们如果知道了客户端的IP和端口号的话,那么这些都不是问题了);之所以这样详细的解释这个问题,主要是想说明客户端使用这个不带参数的构造方法是可行的,在逻辑上是支持的
3、数据报包的创建
在发送数据和接收数据时都需要将数据进行封装,形成数据报包(Datagram Package),但是发送包和接收包的创建有一些微小的区别:
——发送数据报包的创建
通过类java.net.DatagramPacka(byte [ ] buf , int length ,
InetAddress address , int port ) ;
buf—指定了要发送的数据
length—指定了需要发送的数据的字节数
(如果想将buf中的所有的数据全部发送,那么就是用buf.length就行了)
InetAddress—指定了目的地的网络地址
port—指定目的地的端口号
注意:就像上面说的那样,当我们发送数据的时候,在数据报包中会自动地将发送方的网络地址及端口号也封装在其中,但是这属于额外的信息,而参数length指的只是发送的正文部分的字节数,并不包括这写额外的信息
——接收数据报包的创建
使用java.net.DatagramPackage的另外一个构造方法:
public DatagramPackage(byte[ ] buf , int length) ;
因为在接收数据时我们不需要指定什么网络地址和端口号
注意:由于在另一方发送数据报包时,已经自动的将发送方的网络地址和端口号封装在其中了,随意我们可以通过这个接收到的数据报包得到发送方的网络地址和端口号
4、通过数据报包获取信息
java.netDatagramPackage类的成员方法:
①public byte[ ] getData()
返回数据报包中的数据存储空间,从而获取数据报包中的正文信息
②pubic int getLength()
返回该数据报包中正文的字节长度
③public InetAddress getAddress()
如果该数据包是接收到的数据报包,那么返回的是这个数据报包发送方的网络地址;如果该数据报包是将要向外发送的数据报包,那么返回的是这个数据报包的目的地的网络地址
④public int getPort()
返回端口号,规则和上面的方法一样
5、准备好数据报包后就能够进行数据的发送和接收了
发送和接收数据报包都需要通过我们创建的数据报包套接字来完成,即调用java.net.DatagramSocket成员方法
——发送数据报包
public void send( DatagramPackage p )
throws IOException
——接收数据报包
public void receive( DatagramPackage p)
throws IOException
对于receive这个方法,我们要多说几句:这个方法显然是一个阻塞方法,和accept类似,当我们在一方调用了这个方法之后,就会进入一种阻塞状态,等待符合要求的数据报包的到达,否则我们想如果这个方法不是一个阻塞方法的话,就根本不可能接收到数据报包
6、通讯结束
当通讯结束之后,我们要将创建的数据报包套接字对象关闭
调用java.netDatagramSocket的成员方法:
pubic void close ()
下面通过一个简单地例程来说明具体的工作
服务器端:

客户端:

分析:
注意
①要先将服务器端的程序运行起来,之后在运行客户端的程序,否则客户端发送的数据报包会“查无此人”,而被丢弃,服务器端就不会接收到这个数据报包了
②public Data() 创建一个事件对象,保存当前的时间

浙公网安备 33010602011771号