Java 数据报
TCP/IP风格的网络提供了一个序列化的、可预测的、可靠的数据包流。然而,这并不是没有代价的。TCP包括处理拥挤网络上的拥堵控制的算法,以及对数据包丢失的悲观预期。这导致了低效的数据传输方式。
通过可靠通道(如TCP套接字)进行通信的客户和服务器之间有一个专门的点对点通道。为了通信,他们建立一个连接,传输数据,然后关闭连接。所有通过信道发送的数据都会按照发送时的顺序接收。这是由信道保证的。
相比之下,通过数据包通信的应用程序发送和接收完全独立的信息包。这些客户和服务器没有也不需要一个专门的点对点信道。数据包对其目的地的交付是没有保证的。它们到达的顺序也是如此。
数据报
数据报是在网络上发送的独立的、自成一体的消息,其到达、到达时间和内容不受保证。
- 数据报作为一种替代方式发挥着重要作用。
- 数据报是机器之间传递的信息束。一旦数据报被发布到它的预定目标,就不能保证它一定会到达,甚至不能保证有人会在那里抓住它。
- 同样,当数据报被收到时,也不能保证它在运输过程中没有被损坏,也不能保证发送它的人仍然在那里收到回应,这是需要注意的关键点。
Java通过使用两个类在UDP(用户数据报协议)协议的基础上实现数据报。
- DatagramPacket 对象是数据容器。
- DatagramSocket 是用来发送或接收DatagramPacket的机制。
DatagramSocket类
DatagramSocket定义了四个公共构造函数。它们在这里显示。
- DatagramSocket( ) 抛出SocketException: 它创建了一个绑定到本地计算机上任何未使用端口的DatagramSocket。
- DatagramSocket(int port) throws SocketException : 它创建一个绑定到port指定端口的DatagramSocket。
- DatagramSocket(int port, InetAddress ipAddress) throws SocketException : 它构造一个绑定到指定端口和InetAddress的DatagramSocket。
- DatagramSocket(SocketAddress address) throws SocketException : 它构造了一个绑定到指定SocketAddress的DatagramSocket。
SocketAddress是一个抽象类,由具体类InetSocketAddress实现。InetSocketAddress封装了一个带有端口号的IP地址。如果在创建套接字时发生错误,都可以抛出一个SocketException。DatagramSocket定义了许多方法。其中最重要的两个方法是send( )和receive( ),它们在这里显示。
- void send(DatagramPacket packet) throws IOException
- void receive(DatagramPacket packet) throws IOException
send( ) 方法将数据包发送到packet所指定的端口。receive方法等待从packet指定的端口接收数据包,并返回结果。
其他方法使你能够访问与DatagramSocket相关的各种属性。下面是一个样本。
功能介绍 | 使用方法 |
---|---|
InetAddress getInetAddress( ) | 如果套接字被连接,则返回该地址。否则,返回null。 |
int getLocalPort( ) | 返回本地端口的号码。 |
int getPort( ) | 返回套接字所连接的端口的号码。如果套接字没有连接到一个端口,它返回-1。 |
boolean isBound( ) | 如果套接字被绑定到一个地址,则返回true。否则返回false。 |
boolean isConnected( ) | 如果套接字连接到一个服务器上,则返回true。否则返回false。 |
void setSoTimeout(int millis) throws SocketException | 将超时时间设置为以毫秒为单位的超时数。 |
DatagramPacket类
DatagramPacket定义了几个构造函数。这里显示了四个。
- DatagramPacket(byte data[ ], int size) : 它指定了一个接收数据的缓冲区和一个数据包的大小。它用于通过DatagramSocket接收数据。
- DatagramPacket(byte data[ ], int offset, int size) : 它允许你指定一个缓冲区的偏移量,数据将被存储在这个缓冲区。
- DatagramPacket(byte data[ ], int size, InetAddress ipAddress, int port) : 它指定了一个目标地址和端口,DatagramSocket使用它们来决定数据包中的数据将被发送到哪里。
- DatagramPacket(byte data[ ], int offset, int size, InetAddress ipAddress, int port) : 它将数据包从指定的偏移量开始传输。
可以把前两种形式看作是建立一个 “in box”,后两种形式看作是塞进一个信封并编入地址。
DatagramPacket定义了几个方法,包括这里显示的方法,可以访问数据包的地址和端口号,以及原始数据和它的长度。一般来说,get方法用于接收的数据包,set方法用于将要发送的数据包。
功能说明 | 用法 |
---|---|
InetAddress getAddress( ) | 返回源地址(对于正在接收的数据包)或目的地地址(对于正在发送的数据包)。 |
byte[ ] getData( ) | 返回数据报中包含的数据字节数组。主要用于在收到数据报后从数据报中检索数据。 |
int getLength( ) | 返回包含在字节数组中的有效数据的长度,这些数据将从getData( ) 方法中返回。这可能不等于整个字节数组的长度。 |
int getOffset( ) | 返回数据的起始索引。 |
int getPort( ) | 返回端口号。 |
void setAddress(InetAddress ipAddress) | 设置一个数据包将被发送到的地址。该地址由ipAddress指定。 |
void setData(byte[ ] data) | 设置数据为data,偏移量为0,长度为数据中的字节数。 |
void setData(byte[ ] data, int idx, int size) | 将数据设置为data,偏移量设置为idx,长度设置为size。 |
void setLength(int size) | 将数据包的长度设置为size。 |
void setPort(int port) | 将端口设置为端口。 |
一个数据报例子
下面的例子实现了一个非常简单的网络通信客户端和服务器。消息被输入到服务器的窗口中,然后通过网络写入客户端,在那里被显示。
// Java program to illustrate datagrams
import java.net.*;
class WriteServer {
// Specified server port
public static int serverPort = 998;
// Specified client port
public static int clientPort = 999;
public static int buffer_size = 1024;
public static DatagramSocket ds;
// an array of buffer_size
public static byte buffer[] = new byte[buffer_size];
// Function for server
public static void TheServer() throws Exception
{
int pos = 0;
while (true) {
int c = System.in.read();
switch (c) {
case -1:
// -1 is given then server quits and returns
System.out.println("Server Quits.");
return;
case '\r':
break; // loop broken
case '\n':
// send the data to client
ds.send(new DatagramPacket(buffer, pos,
InetAddress.getLocalHost(), clientPort));
pos = 0;
break;
default:
// otherwise put the input in buffer array
buffer[pos++] = (byte)c;
}
}
}
// Function for client
public static void TheClient() throws Exception
{
while (true) {
// first one is array and later is its size
DatagramPacket p = new DatagramPacket(buffer, buffer.length);
ds.receive(p);
// printing the data which has been sent by the server
System.out.println(new String(p.getData(), 0, p.getLength()));
}
}
// main driver function
public static void main(String args[]) throws Exception
{
// if WriteServer 1 passed then this will run the server function
// otherwise client function will run
if (args.length == 1) {
ds = new DatagramSocket(serverPort);
TheServer();
}
else {
ds = new DatagramSocket(clientPort);
TheClient();
}
}
}
这个示例程序被DatagramSocket构造函数限制为在本地机器的两个端口之间运行。要使用该程序,请运行
java WriteServer
在一个窗口中;这将是客户端。然后运行
java WriteServer 1
这将是服务器。在服务器窗口中输入的任何内容都将在收到换行后被发送到客户端窗口。