Note
Java automaycznie wyśle pakiet broadcast jeśli poprosimy ją o wysłanie danych na adres broadcast.
import java.net.InetAddress;
import java.net.UnknownHostException;
public class Config {
public static final int PORT = 9000;
public static final int BUFFER_SIZE = 1024;
public static final InetAddress MULTICAST_ADDRESS;
public static final int MULTICAST_PORT = 9000;
static {
try{
MULTICAST_ADDRESS = InetAddress.getByName("239.255.42.99");
}catch (UnknownHostException e){
throw new RuntimeException(e);
}
}
}
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UDPServer {
public static void main(String[] args) throws Exception{
//Otwarcie gniazda z okreslonym portem
DatagramSocket datagramSocket = new DatagramSocket(Config.PORT);
byte[] byteResponse = "OK".getBytes("utf8");
while (true){
DatagramPacket recievedPacket = new DatagramPacket( new byte[Config.BUFFER_SIZE], Config.BUFFER_SIZE);
datagramSocket.receive(recievedPacket);
int length = recievedPacket.getLength();
String message = new String(recievedPacket.getData(), 0, length, "utf8");
// Port i host, ktory wyslal nam zapytanie
InetAddress address = recievedPacket.getAddress();
int port = recievedPacket.getPort();
System.out.println(message);
Thread.sleep(1000); //oczekiwanie nie jest niezbedne
DatagramPacket response = new DatagramPacket(byteResponse, byteResponse.length, address, port);
datagramSocket.send(response);
}
}
}
Przygotowanie do odbierania połączeń UDP na zadanym portcie:
DatagramSocket datagramSocket = new DatagramSocket(Config.PORT);
Stworzenie pakietu który będzie odbierał dane:
DatagramPacket recievedPacket = new DatagramPacket( new byte[Config.BUFFER_SIZE], Config.BUFFER_SIZE);
Odebraie pakietu:
datagramSocket.receive(recievedPacket);
Tutaj jest kolejny detal implementacyjny w Javie: musimy przekształcić ciąg bajtów do instancji klasy string. Zakładamy że dane w pakiecie kodowane są za pomocą utf-9.
int length = reclievedPacket.getLength();
String message =
new String(reclievedPacket.getData(), 0, length, "utf8");
Wysłanie odpowiedzi:
byte[] byteResponse = "OK".getBytes("utf8");
DatagramPacket response = new DatagramPacket(byteResponse, byteResponse.length, address, port);
Oprogramowanie klienta UDP jest również relatywnie proste.
Note
Nasz klient przyjmuje z linii komend dwa argumenty: adres na który wysyła wiadomość oraz treść wiadomości.
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketTimeoutException;
public class UDPClient {
public static void main(String[] args) throws IOException {
String message = "tekst";
InetAddress serverAddress = InetAddress.getByName("194.29.174.217"); //adres serwera
System.out.println(serverAddress);
DatagramSocket socket = new DatagramSocket(); //Otwarcie gniazda
byte[] stringContents = message.getBytes("utf8"); //Pobranie strumienia bajtow z wiadomosci
DatagramPacket sentPacket = new DatagramPacket(stringContents, stringContents.length);
sentPacket.setAddress(serverAddress);
sentPacket.setPort(Config.PORT);
socket.send(sentPacket);
DatagramPacket receivedPacket = new DatagramPacket( new byte[Config.BUFFER_SIZE], Config.BUFFER_SIZE);
socket.setSoTimeout(1010);
try{
socket.receive(receivedPacket);
int length = receivedPacket.getLength();
String receivedMessage = new String(receivedPacket.getData(), 0, length, "utf8");
System.out.println("Serwer otrzymal wiadomosc: "+receivedMessage);
}catch (SocketTimeoutException ste){
System.out.println("Serwer nie odpowiedzial, byc moze dostal wiadomosc albo nie...");
}
}
}
Wybieramy do jakiego adresu wysyłamy informacje:
InetAddress serverAddress = InetAddress.getByName("194.29.174.217");
Wysłanie pakietu:
byte[] stringContents = message.getBytes("utf8"); //Pobranie strumienia bajtów z wiadomosci
DatagramPacket sentPacket = new DatagramPacket(stringContents, stringContents.length);
sentPacket.setAddress(serverAddress);
sentPacket.setPort(Config.PORT);
socket.send(sentPacket);
Odebranie odpowiedzi.
Tutaj musimy się na chwilę zatrzymać: w TCP moglibyśmy po prostu poczekać na odpowiedź od serwera, tutaj nie możemy tak zrobić — przecież odpowiedź od serwera może po prostu nie nadejść... należy więc powiedzieć socketowi: Poczekaj określony czas na odpowiedż, jeśli nie nadejdzie ona zgłoś wyjątek.
Ustawienie okresu oczekiwania na odpowiedź:
Note
Argument metody setSoTimeout to maksymalny czas oczekiwania na odpowiedź w milisekundach.
socket.setSoTimeout(1010);
Odebranie danych:
DatagramPacket receivedPacket = new DatagramPacket( new byte[Config.BUFFER_SIZE], Config.BUFFER_SIZE);
socket.setSoTimeout(1010);
try{
socket.receive(receivedPacket);
int length = receivedPacket.getLength();
String receivedMessage = new String(receivedPacket.getData(), 0, length, "utf8");
System.out.println("Serwer otrzymal wiadomosc: "+receivedMessage);
}
catch (SocketTimeoutException ste){
System.out.println("Serwer nie odpowiedzial, byc moze dostal wiadomosc albo nie...");
}
(Unicast) W parach modyfikujemy powyższe przykłady:
Klient:
Serwer:
(Broadcast) Tworzymy program, który pozwala na sprawdzenie listy obecności na zajęciach (widocznej dla każdego użytkownika sieci).
W parach tworzymy jeden program, który wysyła i odbiera dane jednocześnie (2 wątki):
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketTimeoutException;
public class MulticastServer {
public static void main(String[] args) throws Exception{
DatagramSocket s = new DatagramSocket();
byte[] message = "Test".getBytes("utf8");
while (true){
DatagramPacket packet = new DatagramPacket(message, message.length);
packet.setPort(9200);
packet.setAddress(InetAddress.getByName("224.0.0.40"));
s.send(packet);
System.out.println("Wyslalem pakiet");
Thread.sleep(1000); //w ms
}
}
}
Wysłanie pakietu na grupę multicast:
DatagramPacket packet = new DatagramPacket(message, message.length);
packet.setPort(9200);
packet.setAddress(InetAddress.getByName("224.0.0.40"));
s.send(packet);
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.MulticastSocket;
public class MulticastClient {
public static void main(String[] args) throws Exception{
byte[] responseBytes = "ACK".getBytes();
InetAddress group = InetAddress.getByName("224.0.0.40");
MulticastSocket s = new MulticastSocket(9200);
s.joinGroup(group);
try{
while(true)
{
DatagramPacket recv = new DatagramPacket(new byte[1024], 1024);
s.receive(recv);
String stringMsg = new String(recv.getData(), 0, recv.getLength(), "utf8");
System.err.println("Got message: \"" + stringMsg);
DatagramSocket responseSocket = new DatagramSocket();
DatagramPacket response = new DatagramPacket(responseBytes, responseBytes.length);
response.setAddress(recv.getAddress());
response.setPort(recv.getPort());
Thread.sleep(1000);
responseSocket.send(response);
}
}finally {
s.leaveGroup(group);
}
}
}
Stworzenie gniazda multicast — oraz dołączenie do grupy mulitcast
InetAddress group = InetAddress group = InetAddress.getByName("224.0.0.40");
MulticastSocket s = new MulticastSocket(9200);
s.joinGroup(group);
(Multicast) Przerabiamy program z zadania 2, aby działał na multicast.