devstory

Le Tutoriel de Java DatagramChannel

  1. DatagramChannel
  2. Par exemple
  3. Static Factory methods
  4. Methods

1. DatagramChannel

DatagramChannel est une classe qui représente une connexion ouverte vers un socket de réseau (network socket) et qui utilise le protocole UDP/IP afin de lire ou d'écrire les données sur le réseau (network).
public abstract class DatagramChannel
    extends AbstractSelectableChannel
    implements ByteChannel, ScatteringByteChannel, GatheringByteChannel, MulticastChannel
UDP
User Datagram Protocol (UDP) (Le protocole de datagramme de l'utilisateur) : En bref, UDP est un protocole avec des règles utilisé pour diviser les données en petits paquets appelés datagramme(s) au niveau de l'expéditeur et des règles pour les concaténer ensemble au niveau du récepteur. UDP convient à la transmission de données sur le réseau dans les applications nécessitant une faible latence.
1 Datagram = 1 Gram of data (1 gramme de données). Datagram n'a pas de sens quantitatif. Sa taille n'est pas fixe et n'est censée être qu'un très petit paquet de données.
UDP/IP
Les règles définies par UDP ne suffisent pas pour envoyer des données entre 2 appareils, il faut donc les combiner avec Internet Protocol (IP). Et on a le protocole UDP/IP :
  • Internet Protocol (IP): aide à déterminer l'emplacement des appareils sur le réseau et à transporter les paquets de données sur Internet. Spécifiquement dans ce cas, il transportera des paquets de Datagram.
Les paquets envoyés via UDP/IP ne dispose d'aucune information de séquence et ne sont pas vérifiés pour voir s'ils arrivent comme prévu. Avec un moyen d'envoi aussi simple, UDP/IP est plus rapide mais moins fiable que d'autres protocoles, tels que TCP/IP. Cette vitesse provoque un compromis. Si un paquet de données est perdu en transit, il ne sera pas renvoyé. Par conséquent, les applications qui utilisent UDP doivent être capables de tolérer les erreurs, les pertes et les duplications.
Techniquement parlant, la perte de données ne représente pas une vulnérabilité dans UDP. La cause en est généralement la qualité de l'infrastructure réseau, des routeurs réseau,...
Des exemples sur quelques types de services qui utilisent souvent UDP :
UDP est un protocole idéal pour les applications réseau nécessitant une faible latence, telles que les jeux, les communications vocales et vidéo. Ces exemples peuvent subir des pertes de données sans affecter négativement la qualité perçue. Dans certains cas, cependant, des techniques de correction d'erreur directe sont utilisées en plus de l'UDP pour améliorer la qualité audio et vidéo, malgré quelques pertes.
Voir plus d'articles approfondis sur UDP/IP et TCP/IP:
  • User Datagram Protocol - UDP
  • Transmission Control Protocol - TCP
La hiérarchie des classes et des interfaces est liée à la classe DatagramChannel :

2. Par exemple

Dans cet exemple, on va envoyer un message entre 2 programmes exécutés sur 2 ordinateurs différents. Voici une illustration de l'exemple :
ReceiverProgram : Le programme récepteur doit ouvrir un DatagramChannel et écouter à son adresse IP avec un certain port, par exemple, "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 : Le programme d'envoi (message) doit ouvrir un DatagramChannel et envoyer le message à l'adresse d'écoute du programme de réception (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();
    }
}
Pour tester l'application, vous devez d'abord exécuter la classe ReceiverProgram, puis exécuter la classe 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

Les méthodes d'usine statiques :
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
Les méthodes héritées des interfaces ReadableByteChannel et WriteableChannel :
public abstract int read(ByteBuffer dst) throws IOException;  
public abstract int write(ByteBuffer src) throws IOException;
Méthodes héritées des interfaces ScatteringByteChannel et GatheringByteChannel :
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
Les méthodes héritées de l'interface SelectableChannel :
public final int validOps()
  • Le Tutoriel de Java SelectableChannel
Les méthodes héritées des interfaces NetworkChannel et MulticastChannel :
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
Les autres méthodes :
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;