基于JAVA的电子邮件接收系统设计外文翻译资料
2022-09-09 16:13:32
UDP
Previous chapters discussed network applications that run on top of the TCP transport layer protocol. TCP is designed for reliable transmission of data. If data is lost or damaged in transmission, TCP ensures that the data is resent. If packets of data arrive out of order, TCP puts them back in the correct order. If the data is coming too fast for the connection, TCP throttles the speed back so that packets wonrsquo;t be lost. A program never needs to worry about receiving data that is out of order or incorrect. However, this reliability comes at a price. That price is speed. Establishing and tearing down TCP connections can take a fair amount of time, particularly for protocols such as HTTP, which tend to require many short transmissions. The User Datagram Protocol (UDP) is an alternative transport layer protocol for sending data over IP that is very quick, but not reliable. When you send UDP data, you have no way of knowing whether it arrived, much less whether different pieces of data arrived in the order in which you sent them. However, the pieces that do arrive generally arrive quickly.
The UDP Protocol
The obvious question to ask is why anyone would ever use an unreliable protocol. Surely, if you have data worth sending, you care about whether the data arrives correctly? Clearly, UDP isnrsquo;t a good match for applications like FTP that require reliable transmission of data over potentially unreliable networks. However, there are many kinds of applications in which raw speed is more important than getting every bit right. For example, in real-time audio or video, lost or swapped packets of data simply appear as static. Static is tolerable, but awkward pauses in the audio stream, when TCP requests a retransmission or waits for a wayward packet to arrive, are unacceptable. In other applications, reliability tests can be implemented in the application layer. For example, if a client sends a short UDP request to a server, it may assume that the packet is lost if no response is returned within an established period of time; this is one way the DomainName System (DNS) works. (DNS can also operate over TCP.) In fact, you could implement a reliable file transfer protocol using UDP, and many people have: Network File System (NFS), Trivial FTP (TFTP), and FSP, a more distant relative of FTP, all use UDP. (The latest version of NFS can use either UDP or TCP.) In these protocols, the application is responsible for reliability; UDP doesnrsquo;t take care of it (the application must handle missing or out-of-order packets). This is a lot of work, but therersquo;s no reason it canrsquo;t be done—although if you find yourself writing this code, think carefully about whether you might be better off with TCP. The difference between TCP and UDP is often explained by analogy with the phone system and the post office. TCP is like the phone system. When you dial a number, the phone is answered and a connection is established between the two parties. As you talk, you know that the other party hears your words in the order in which you say them. If the phone is busy or no one answers, you find out right away. UDP, by contrast, is like the postal system. You send packets of mail to an address. Most of the letters arrive, but some may be lost on the way. The letters probably arrive in the order in which you sent them, but thatrsquo;s not guaranteed. The farther away you are from your recipient, the more likely it is that mail will be lost on the way or arrive out of order. If this is a problem, you can write sequential numbers on the envelopes, then ask the recipients to arrange them in the correct order and send you mail telling you which letters arrived so that you can resend any that didnrsquo;t get there the first time. However, you and your correspondent need to agree on this protocol in advance. The post office will not do it for you. Both the phone system and the post office have their uses. Although either one could be used for almost any communication, in some cases one is definitely superior to the other. The same is true of UDP and TCP. The past several chapters have all focused on TCP applications, which are more common than UDP applications. However, UDP also has its place; in this chapter, wersquo;ll look at what you can do with UDP. If you want to go further, the next chapter describes multicasting over UDP. A multicast socket is a fairly simple variation on a standard UDP socket. Javarsquo;s implementation of UDP is split into two classes: DatagramPacket and Datagram Socket. The DatagramPacket class stuffs bytes of data into UDP packets called datagrams and lets you unstuff datagrams that you receive. A DatagramSocket sends as well as receives UDP datagrams. To send data, you put the data in a DatagramPacket and send the packet using a DatagramSocket. To receive data, you take a DatagramPacket object from a DatagramSocket and then inspect the contents of the packet. The sockets themselves are very simple creatures. In UDP, everything about a datagram, including the address to which it is directed, is included in the packet itself; the socket only needs to know the local port on which to listen or send. This division of labor contrasts with the Socket and ServerSocket classes used by TCP. First, UDP doesnrsquo;t have any notion of a unique connection between two hosts. Onesocket sends and receives all data directed to or from a port without any concern for who the remote host is. A single DatagramSocket can send data to and receive data from many independent hosts. The socket isnrsquo;t dedicated to a single connection, as it is in TCP. In fact, UDP doesnrsquo;t have any concept of a connection between two hosts; it only knows about individual datagrams. Figuring out who sent what data is the applicationrsquo;s responsibility. Second, TCP sockets treat a network connection as a stream: you send and receive data with input and output streams that you get from the socket. UDP doesnrsquo;t support this; you always work with i
剩余内容已隐藏,支付完成后下载完整资料
UDP
前面几章讨论了在TCP传输层协议之上运行的网络应用程序。TCP是为数据的可靠传输而设计的。如果数据在传输中丢失或损坏,TCP会保证再次发送数据。如果数据包乱序到达,TCP会将其置回正确的顺序。对于连接来说,如果数据到来的速度太快,TCP会降低速度,以免数据包丢失。程序永远不需要担心接收到乱序或不正确的数据。不过,这种可靠性是有代价的。这个代价就是速度。建立和撤销TCP连接会花费相当长的时间,对于某些协议,特别是像HTTP这样的协议,这是无法接受的(这些协议往往需要多个短时间的数据传输)。
用户数据报协议(User Datagram Protocol, UDP)是在IP之上发送数据的另一种传输层协议,速度很快,但不可靠。当发送UDP数据时,无法知道数据是否会到达,也不知道数据的各个部分是否会以发送时的顺序到达。不过,确实能到达的部分一般都会很快到达。
UDP协议
对此有一个很明显的问题,为什么有人要是用一个不可靠的协议呢?如果有需要发送的数据,你当然会关心数据是否正确到达,对不对?很显然,对于类似FTP的应用程序,由于需要通过可能不可靠的网络进行可靠的数据传输,因此UDP不是一个好的选择。不过,另外还有很多其他类型的应用程序。在这些应用程序中,保持最快的速度比保证每一位数据都正确更为重要。例如,在实时音频或视频中,丢失或交换数据包只会作为干扰出现。干扰是可以容忍的,但当TCP请求重传或等待数据包到达而它却迟迟不到时,音频流中就会出现尴尬的停顿,这是让人无法接受的。在其他应用程序中,可以在应用层实现可靠性测试。例如如果P客户端向服务器发送了一个短的UDP请求,倘若指定定时间内没有响应返回,它会认为这个包已丢失。域名系统(Domain Name System,DNS)就采取这样的工作方式(DNS也可以在TCP之上工作)。事实上,你也可以用UDP实现一个可靠的文件传输协议,而且很多人确实已经这样做了:网络文件系统(Network File System, NFS)、简单FTP (Trivial FTP, TFTP)和FSP(这是与FTP关系较远的一种协议)都使用了UDP (NFS的最新版本可以使用UDP或TCP)。在这些协议中,由应用程序负责可靠性。UDP不关心这一点(也就是说,应用程序必须处理丢失或乱序的包)。这会带来大量工作,但并不表示不能这样做,不过倘若要由你自己来编写这些代码,你就要仔细考虑一下,可能使用TCP会更好。
通常可以用电话系统和邮局的关系来对照解释TCP与UDP的区别。TCP就像电话系统。当你拨号时,电话会得到应答,在双方之间建立起一个连接。当你说话时,你知道另一方会以你说的顺序听到你讲的话。如果电话忙或没有人应答,你会马上发现。相反,UDP就像邮局系统。你向一个地址发送邮包。大多数信件都会到达,但有些可能会在路上丢失。信件可能以发送的顺序到达,但这一点无法保证。离接收方越远,邮件就越有可能在路上丢失或乱序到达。如果这对你来说很重要,你可以在信封上写上序号,然后要求接收方以正确的顺序排列,并发邮件来告诉你哪些信件已经到达,这样你就可以重新发送第一次没有到达的信件。不过,你和对方需要预先协商好这个协议。邮局不会为你做这件事。
电话系统和邮局都有各自的用处。尽管它们几乎都可以用于任何通信,但是在某些特定情况下,二者之间肯定有优劣之分。UDP和TCP也是这样。前面几章重点介绍TCP应用,它们比UDP应用更常见。不过,UDP也有自己的位置。在本章中,我们将看到用UDP能做什么。如果希望进一步深入,下一章会介绍UDP之上的组播。组播socket是标准UDP socket的一种相当简单的变体。
Java中UDP的实现分为两个类:DatagramPacket和DatagramSocket, DatagramPacket类将数据字节填充到UDP包中,这称为数据报(datagram),由你来解包接收的数据报。DatagramSocket可以收发UDP数据报。为发送数据,要将数据放到DatagramPacket中,使用DatagramSocket来发送这个包。要接收数据,可以从DatagramSocket中接收一个DatagramPacket对象,然后检查该包的内容。Socket本身非常简单。在UDP中,关于数据报的所有信息(包括发往的目标地址)都包含在包本身中。Socket只需要了解在哪个本地端口监听或发送。
这种职责划分与TCP使用的Socket和ServerSocket有所不同。首先,UDP没有两台主机间唯一连接的概念。一个Socket会收发所有指向指定端口的数据,而不需要知道对方是哪一个远程主机。一个。atagramSocket可以从多个独立主机收发数据。与TCP不同,这个Socket并不专用于一个连接。事实上,UDP没有任何两台主机之间连接的概念,它只知道单个数据报。要确定由谁发送什么数据,这是应用程序的责任。其次,TCP socket把网络连接看作是流:通过从Socket得到的输入和输出流来收发数据。UDP不支持这一点,你处理的总是单个数据报包。填充在一个数据报的所有数据会以一个包的形式进行发送,这些数据作为一个组要么全部接收,要么完全丢失。一个包不一定与下一个包相关。给定两个包,没有办法确定哪个先发送哪个后发送。对于流来说,必须提供数据的有序队列,与之不同,数据报会尽可能快地蜂拥到接收方,就像一大群人挤公共汽车一样。而在有些情况下,如果公共汽车太挤了,有些包就会像一些不走运的人一样,可能被挤在外面,继续在公共汽车站上等候。
UDP客户端
先来看一个简单的例子。类似于第8章的“用Socket从服务器读取”一节,我们将连接国家标准与技术研究院(National Institute for Standards and Technology, NIST)的daytime服务器,请求当前时间。不过,这一次将使用UDP而不是TCP。应该记得,daytime服务器在端口13监听,这个服务器会以人可读的格式发送时间,并关闭Socket.
现在来看如何通过编程使用UDP获取同样的数据。首先,在端口0打开一个Socket:
DatagramSocket socket=new DatagramSocket(o);
这与TCP socket有很大不同。你只需要指定要连接的一个本地端口。Socket并不知道远程主机或地址是什么。通过指定端口0,就是在请求Java为你随机选择一个可用的端口,就像是服务器Socket-样。
下一步是可选的,不过强烈建议你完成这一步。使用setSoTimeout()方法在连接上设置一个超时时间.超时时间以毫秒为单位来度量,所以下面这个语句设置Socket在10秒无响应后就会超时:
socket.setSoTimeout(l0000);
超时对于UDP比TCP甚至更重要,因为TCP中会导致IOException异常的很多问题在UDP中只会悄无声息地失败。例如,如果远程主机未在目标端口监听,你就永远也不会收到回音。
接下来需要建立数据包。你要建立两个数据包,一个是要发送的数据包,另一个是要接收的数据包。对于daytime协议,数据包里有哪些数据并不重要,不过一定要指出要连接的远程主机和远程端口:
InetAddress host=InetAddress.getByName('time.nist.gov');
DatagramPacket request=new DatagramPacket(new byte[i], 1, host, 13);
接收服务器响应的数据包只包含一个空的byte数组。这个数组要足够大,可以包含整个个响应。如果它太小,就会悄悄地截断响应,1KB大小的空间应该足够了:
byte[] data=new byte[1024];
DatagramPacket response=new DatagramPacket(data, data.length);
现在已经准备就绪。首先在这个Socket上发送数据包,然后接收响应:
socket.send(request);
socket.receive(response);
最后,从响应中提取字节,将它们转换为可以显示给最终用户的字符串:
String daytime=new String(response.getData(), 0, response.getLength(),
'US-ASCII');
System.out.println(daytime);.
构造函数以及send()和:eceive()方法都可能抛出一个IOException,所以通常要把它们都包围在一个try块中。在Java 7中,DatagramSocket实现TAUtocloseable,所以还可以使用try-with-resources
try (DatagramSocket socket=new DatagramSocket(o)){
//连接到服务器hellip;
}catch (IOException ex){
System.err.println('Could not connect to time.nist.gov');
}
在Java 6和之前的版本中,可能要在一个finally块中显式地关闭Socket,来释放这个Socket占用的资源:
Datagramsocket socket=null;
try{
Socket=new DatagramSocket(o);
//连接到服务器.。.
}catch(IOException ex){
System.err.println(ex);
}finally{
if (socket I=null){
try{
socket.close();
}catch(I0Exception ex){
//忽略
}
}
}
示例12-1将以上内容汇集在一起。
示例12-1:一个daytime协议客户端
import java.io.*;
import java.net.*;
public class DaytimeUDPClient{
private final static int PORT=13;
private static final String HOSTNAME='time.nist.gov';
public static void main(String[] args){
try (DatagramSocket socket=new DatagramSocket(0)){
socket.setSoTimeout(10000);
InetAddress host=InetAddress.getByName(HOSTNAME);
DatagramPacket request=new DatagramPacket(new byte[i], 1, host,PORT);
DatagramPacket response=new DatagramPacket(new byte[1024], 1024);
socket.send(request);
socket.receive(response);
String result=new String(response.getData(), 0, response.getLength(),
'US-ASCII');
System.out.println(result);
)catch (I0Exception ex){
ex.printStackTrace();
}
}
}
就像用TCP连接一样,输出基本上是一样的:
$java DaytimeUDPClient
56375 13-04-11 19:55:22 50 0 0 843.6 UTC(NIST)*
UDP服务器
UDP服务器几乎遵循与UDP客户端同样的模式,只不过通常在发送之前会先接收,而且不会选择要绑定的匿名端口。与TCP不同,并没有单独的DatagramServerSocket类。
例如,假设要在UDP上实现一个daytime服务器。首先在一个已知端口上打开一个数据报Socket。对于daytime协议,这个端口为13:
Datagramsocket socket=new Datagramsocket(13);
与TCP Socket类似,在UNIX系统(包括Linux和Mac OS X)上,要绑定一个小于1024的端口,必须作为root用户运行。可以使用sud。来运行程序,或者只需改为大于或等于1024的某个端口。
接下来,创建一个将接收请求的数据包。要提供一个将存储入站数据的byte数组,数组中的偏移量,以及要存储的字节数。在这里,将建立一个可以从0开始存储1024字节的数据包,
DatagramPacket request=new DatagramPacket(new byte[1024], 0, 1
剩余内容已隐藏,支付完成后下载完整资料
资料编号:[146127],资料为PDF文档或Word文档,PDF文档可免费转换为Word