Java中的数据报
TCP/IP 风格的网络提供了一个序列化的、可预测的、可靠的数据包数据流。然而,这并非没有代价。 TCP 包括处理拥挤网络上的拥塞控制的算法,以及对丢包的悲观预期。这导致传输数据的方式效率低下。
通过可靠通道(例如 TCP 套接字)进行通信的客户端和服务器在它们之间具有专用的点对点通道。为了进行通信,它们建立连接,传输数据,然后关闭连接。通过通道发送的所有数据都按照发送的顺序接收。这是由渠道保证的。
相反,通过数据报通信的应用程序发送和接收完全独立的信息包。这些客户端和服务器没有也不需要专用的点对点通道。无法保证将数据报传送到其目的地。他们到达的顺序也不是。
数据报
数据报是通过网络发送的独立的、自包含的消息,其到达、到达时间和内容都无法保证。
- 作为替代方案,数据报起着至关重要的作用。
- 数据报是在机器之间传递的信息包。一旦数据报被释放到它的预定目标,就不能保证它会到达,甚至不能保证有人会在那里抓住它。
- 同样,当收到数据报时,不能保证它在传输过程中没有损坏,或者发送它的人仍然在那里接收响应,这是需要注意的关键点。
Java通过使用两个类在 UDP(用户数据报协议)协议之上实现数据报:
- DatagramPacket对象是数据容器。
- DatagramSocket是用于发送或接收 DatagramPackets 的机制。
数据报套接字类
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) 抛出 IOException
- 无效接收(DatagramPacket 数据包)抛出 IOException
send() 方法将数据包发送到数据包指定的端口。 receive 方法等待从 packet 指定的端口接收到一个数据包并返回结果。
其他方法使您可以访问与 DatagramSocket 关联的各种属性。这是一个样本:
Function | Usage |
---|---|
InetAddress getInetAddress( ) | If the socket is connected, then the address is returned. Otherwise, null is returned. |
int getLocalPort( ) | Returns the number of the local port. |
int getPort( ) | Returns the number of the port to which the socket is connected. It returns –1 if the socket is not connected to a port. |
boolean isBound( ) | Returns true if the socket is bound to an address. Returns false otherwise. |
boolean isConnected( ) | Returns true if the socket is connected to a server. Returns false otherwise. |
void setSoTimeout(int millis) throws SocketException | Sets the time-out period to the number of milliseconds passed in millis. |
数据报包类
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) :它将数据包从指定的偏移量开始传输到数据中。
将前两种形式视为构建“收件箱”,将后两种形式视为填充和寻址信封。
DatagramPacket 定义了几种方法,包括此处显示的方法,这些方法可以访问数据包的地址和端口号,以及原始数据及其长度。通常,get 方法用于接收到的数据包,set 方法用于将要发送的数据包。
Function | Usage |
---|---|
InetAddress getAddress( ) | Returns the address of the source (for datagrams being received) or destination (for datagrams being sent). |
byte[ ] getData( ) | Returns the byte array of data contained in the datagram. Mostly used to retrieve data from the datagram after it has been received. |
int getLength( ) | Returns the length of the valid data contained in the byte array that would be returned from the getData( ) method. This may not equal the length of the whole byte array. |
int getOffset( ) | Returns the starting index of the data. |
int getPort( ) | Returns the port number. |
void setAddress(InetAddress ipAddress) | Sets the address to which a packet will be sent. The address is specified by ipAddress. |
void setData(byte[ ] data) | Sets the data to data, the offset to zero, and the length to number of bytes in data |
void setData(byte[ ] data, int idx, int size) | Sets the data to data, the offset to idx, and the length to size. |
void setLength(int size) | Sets the length of the packet to size. |
void setPort(int port) | Sets the port to 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
这将是服务器。在收到换行符后,在服务器窗口中键入的任何内容都将发送到客户端窗口。