openplanning

Hướng dẫn và ví dụ Java DatagramChannel

  1. DatagramChannel
  2. Ví dụ
  3. Static Factory methods
  4. Methods

1. DatagramChannel

DatagramChannel là một lớp đại diện cho kết nối mở tới một ổ cắm mạng (network socket) và sử dụng giao thức UDP/IP để đọc hoặc ghi dữ liệu tới mạng (network).
public abstract class DatagramChannel
    extends AbstractSelectableChannel
    implements ByteChannel, ScatteringByteChannel, GatheringByteChannel, MulticastChannel
UDP
User Datagram Protocol (UDP) (Tạm dịch: Giao thức gói dữ liệu người dùng): Nói ngắn gọn, UDP là một giao thức với các quy tắc để phân chia một dữ liệu thành các gói nhỏ được gọi là Datagram tại nơi gửi và quy tắc để ghép chúng lại với nhau tại nơi nhận. UDP phù hợp cho việc truyền truyền dữ liệu trên môi trường mạng trong các ứng dụng yêu cầu độ trễ thấp.
1 Datagram = 1 Gram of data (1 gam dữ liệu). Datagram không có ý nghĩa về mặt định lượng. Kích thước của nó không cố định và chỉ có ý nghĩa là một gói dữ liệu rất nhỏ.
UDP/IP
Các quy tắc được thiết lập bởi UDP là không đủ để gửi dữ liệu giữa 2 thiết bị, vì vậy nó cần được kết hợp với giao thức Internet (Internet Protocol - IP). Và chúng ta có giao thức UDP/IP:
  • Internet Protocol (IP): Giúp xác định vị trí của các thiết bị trên mạng, và vận chuyển các gói dữ liệu trên Internet. Cụ thể trong trường hợp này nó sẽ vận chuyến các gói Datagram.
Các gói dữ liệu được gửi đi theo giao thức UDP/IP không có thông tin thứ tự, và cũng không được kiểm tra liệu chúng có đến nơi như dự định hay không. Với cách thức gửi đơn giản như vậy, UDP/IP nhanh hơn nhưng kém tin cậy hơn so với các giao thức khác, chẳng hạn TCP/IP. Tốc độ này tạo ra sự đánh đổi. Nếu một gói dữ liệu bị mất trong quá trình truyền tải, nó sẽ không được gửi lại. Do đó, các ứng dụng sử dụng UDP phải có khả năng chịu được lỗi, mất mát và trùng lặp.
Về mặt kỹ thuật, việc mất mát dữ liệu không phải là một lỗ hổng trong UDP. Nguyên nhân dẫn tới điều này thường là do chất lượng cơ sở hạ tầng mạng, các thiết bị định tuyến mạng,...
Ví dụ về một một vài loại dịch vụ thường sử dụng UDP:
UDP là một giao thức lý tưởng cho các ứng dụng mạng yêu cầu độ trễ thấp, chẳng hạn như trong trò chơi, liên lạc thoại và video. Những ví dụ này có thể bị mất một số dữ liệu mà không ảnh hưởng xấu đến chất lượng cảm nhận. Tuy nhiên, trong một số trường hợp, các kỹ thuật sửa lỗi chuyển tiếp được sử dụng ngoài UDP để cải thiện chất lượng âm thanh và video, mặc dù có một số tổn thất.
Xem thêm các bài viết chuyên sâu về UDP/IPTCP/IP:
  • User Datagram Protocol - UDP
  • Transmission Control Protocol - TCP
Hệ thống phân cấp các lớp và interface có liên quan tới lớp DatagramChannel:

2. Ví dụ

Trong ví dụ này chúng ta sẽ gửi một thông điệp giữa 2 chương trình chạy trên 2 máy tính khác nhau. Dưới đây là hình minh hoạ của ví dụ:
ReceiverProgram: Chương trình nhận cần mở một DatagramChannel và lắng nghe ở một địa chỉ IP của nó với một cổng (port) nào đó, chẳng hạn "localhost:9999".
ReceiverProgram.java
package org.o7planning.datagramchannel.ex;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;

public class ReceiverProgram {

    public static DatagramChannel startReceiver() throws IOException {
        DatagramChannel receiver = DatagramChannel.open();
        // Listening SocketAddress
        InetSocketAddress address = new InetSocketAddress("localhost", 9999);
        receiver.bind(address); // The receiver is listening at localhost:9999

        System.out.println("Receiver started at #" + address);
        return receiver;
    }

    public static String receiveMessage(DatagramChannel receiver) throws IOException {
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        SocketAddress senderAddress = receiver.receive(buffer);
        String message = extractMessage(buffer);
        System.out.println("Received message from sender: " + senderAddress);
        return message;
    }

    private static String extractMessage(ByteBuffer buffer) {
        buffer.flip();
        byte[] bytes = new byte[buffer.remaining()];
        buffer.get(bytes);
        String msg = new String(bytes);
        return msg;
    }

    public static void main(String[] args) throws IOException {
        DatagramChannel receiver = startReceiver();
        while (true) {
            String message = receiveMessage(receiver);
            System.out.println(" - Message: " + message);
            if("Bye!".equals(message)) {
                break;
            }
        }
        receiver.close();
        System.out.println("Receiver closed!");
    }
}
SenderProgram: Chương trình gửi (thông điệp) cần mở một DatagramChannel và gửi thông điệp tới địa chỉ đang lắng nghe của chương trình nhận (ReceiverProgram).
SenderProgram.java
package org.o7planning.datagramchannel.ex;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;

public class SenderProgram {

    public static DatagramChannel startSender() throws IOException {
        DatagramChannel sender = DatagramChannel.open();
        // SocketAddress
        SocketAddress address = null;
        sender.bind(address);

        sender.configureBlocking(false);
        return sender;
    }
    public static void sendMessage(DatagramChannel sender, String msg, //
            SocketAddress receiverAddress) throws IOException {
        ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());
        sender.send(buffer, receiverAddress);
    }
    public static void main(String[] args) throws IOException, InterruptedException {
        DatagramChannel sender = startSender();

        String[] messages = new String[] { "Hello", "How are you?", "Bye!" };
        // SocketAddress of the Receiver.
        InetSocketAddress receiverAddress = new InetSocketAddress("localhost", 9999);

        for (String message : messages) {
            // Send message to the Receiver!
            sendMessage(sender, message, receiverAddress);
            Thread.sleep(2 * 1000); // 2 seconds.
        }
        sender.close();
    }
}
Để test ứng dụng, ban đầu bạn cần chạy lớp ReceiverProgram, sau đó chạy lớp SenderProgram:
Output:
Receiver started at #localhost/127.0.0.1:9999
Received message from sender: /127.0.0.1:58179
 - Message: Hello
Received message from sender: /127.0.0.1:58179
 - Message: How are you?
Received message from sender: /127.0.0.1:58179
 - Message: Bye!
Receiver closed!

3. Static Factory methods

Các phương thức nhà máy tĩnh:
public static DatagramChannel open() throws IOException  
public static DatagramChannel open(ProtocolFamily family) throws IOException

4. Methods

public abstract class DatagramChannel
    extends AbstractSelectableChannel
    implements ByteChannel, ScatteringByteChannel, GatheringByteChannel, MulticastChannel
Các phương thức thừa kế từ interface ReadableByteChannelWriteableChannel:
public abstract int read(ByteBuffer dst) throws IOException;  
public abstract int write(ByteBuffer src) throws IOException;
Các phương thức thừa kế từ interface ScatteringByteChannelGatheringByteChannel:
public abstract long read(ByteBuffer[] dsts, int offset, int length) throws IOException;  
public final long read(ByteBuffer[] dsts) throws IOException  

public abstract long write(ByteBuffer[] srcs, int offset, int length) throws IOException;
public final long write(ByteBuffer[] srcs) throws IOException
Các phương thức thừa được thừa kế từ interface SelectableChannel:
public final int validOps()
  • Hướng dẫn và ví dụ Java SelectableChannel
Các phương thức thừa kế từ interface NetworkChannelMulticastChannel:
public abstract SocketAddress getLocalAddress() throws IOException;
public abstract DatagramChannel bind(SocketAddress local) throws IOException;
public abstract <T> DatagramChannel setOption(SocketOption<T> name, T value) throws IOException;

MembershipKey join(InetAddress group, NetworkInterface interf) throws IOException;
MembershipKey join(InetAddress group, NetworkInterface interf, InetAddress source) throws IOException;
  • NetworkChannel
  • MulticastChannel
Các phương thức khác:
public abstract DatagramSocket socket();
public abstract boolean isConnected();
public abstract DatagramChannel connect(SocketAddress remote) throws IOException;
public abstract DatagramChannel disconnect() throws IOException;
public abstract SocketAddress getRemoteAddress() throws IOException;
public abstract SocketAddress receive(ByteBuffer dst) throws IOException;
public abstract int send(ByteBuffer src, SocketAddress target) throws IOException;