📜  Java中的数据报

📅  最后修改于: 2022-05-13 01:54:50.393000             🧑  作者: Mango

Java中的数据报

TCP/IP 风格的网络提供了一个序列化的、可预测的、可靠的数据包数据流。然而,这并非没有代价。 TCP 包括处理拥挤网络上的拥塞控制的算法,以及对丢包的悲观预期。这导致传输数据的方式效率低下。
通过可靠通道(例如 TCP 套接字)进行通信的客户端和服务器在它们之间具有专用的点对点通道。为了进行通信,它们建立连接,传输数据,然后关闭连接。通过通道发送的所有数据都按照发送的顺序接收。这是由渠道保证的。
相反,通过数据报通信的应用程序发送和接收完全独立的信息包。这些客户端和服务器没有也不需要专用的点对点通道。无法保证将数据报传送到其目的地。他们到达的顺序也不是。

数据报

数据报是通过网络发送的独立的、自包含的消息,其到达、到达时间和内容都无法保证。

  • 作为替代方案,数据报起着至关重要的作用。
  • 数据报是在机器之间传递的信息包。一旦数据报被释放到它的预定目标,就不能保证它会到达,甚至不能保证有人会在那里抓住它。
  • 同样,当收到数据报时,不能保证它在传输过程中没有损坏,或者发送它的人仍然在那里接收响应,这是需要注意的关键点。

Java通过使用两个类在 UDP(用户数据报协议)协议之上实现数据报:

  1. DatagramPacket对象是数据容器。
  2. 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 关联的各种属性。这是一个样本:

FunctionUsage
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 SocketExceptionSets 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 方法用于将要发送的数据包。

FunctionUsage
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

这将是服务器。在收到换行符后,在服务器窗口中键入的任何内容都将发送到客户端窗口。