2.3.3 UDP服务器端

与TCP服务器一样,UDP服务器的工作是建立一个通信终端,并被动等待客户端发起连接。但由于UDP是无连接的,UDP通信通过客户端的数据报文初始化,并没有TCP中建立连接那一步。典型的UDP服务器要执行以下三步:

1.创建一个DatagramSocket实例,指定本地端口号,并可以选择指定本地地址。此时,服务器已经准备好从任何客户端接收数据报文。

2.使用DatagramSocket类的receive()方法来接收一个DatagramPacket实例。当receive()方法返回时,数据报文就包含了客户端的地址,这样我们就知道了回复信息应该发送到什么地方。

3.使用DatagramSocket类的send()和receive()方法来发送和接收DatagramPackets实例,进行通信。

下一个示例程序,UDPEchoServer.java,实现了一个UDP版本的回馈服务器。这个服务器非常简单:它不停地循环,接收数据报文后将相同的数据报文返回给客户端。实际上我们的服务器只接收和发送数据报文中的前255(ECHOMAX)个字符,超出的部分将在套接字的具体实现中无提示地丢弃。

UDPEchoServer.java

figure_0046_0041

figure_0047_0042

1.应用程序设置和参数解析:第0~14行

UDPEchoServer只接收一个参数,即该回馈服务器套接字的本地端口号。

2.创建和设置数据报文套接字:第16行

与UDP客户端不同的是,UDP服务器必须显式地设置它的本地端口号,并使客户端知道该端口,否则客户端将不知道应该把回馈请求数据报文发送到什么目的地址。服务器从客户端接收到了回馈数据报文后,能从中获取客户端的地址和端口号。

3.创建数据报文:第17行

UDP消息包含在数据报文中。我们构建了一个DatagramPacket实例,其缓存区最多(ECHOMAX)可容纳255个字节。这个数据报文将同时用来接收回馈请求和发送回馈信息。

4.迭代处理收到的回馈请求:第19~25行

UDP服务器为所有通信使用同一个套接字,这点与TCP服务器不同,TCP服务器为每个成功返回的accept()方法创建一个新的套接字。

·接收回馈请求数据报文,打印其源地址信息:第20~22行

DatagramSocket类的receive()方法将阻塞等待,直到接收到从客户端发来的数据报文(或超时)。由于没有连接,每个数据报文都可能发送自不同的客户端。而数据报文自身就包含了其发送者的(客户端的)源地址和端口号。

·发送回馈信息:第23行

数据包(packet)中已经包含了回馈字符串和回馈目的地址及端口,因此DatagramSocket类的send()方法只是简单地传输之前接收到的数据报文。注意,当我们接收数据报文时,将其地址和端口解释为源地址和端口,而在发送数据报文时,则将其地址和端口称为目的地址和端口。

·重置缓存区大小:第24行

处理了接收到的消息后,数据包的内部长度将设置为刚处理过的消息的长度,而这可能比缓冲区的原始长度短。如果接收新消息前不对内部长度进行重置,后续的消息一旦长于之前的消息,就会被截断。