SK Zadanie 5From Łukasz Graczykowski(Difference between revisions)
Revision as of 08:09, 20 April 2022
UWAGA! Zajęcia 4 - nowa kolejność ZadaniaZadanie 1(Unicast) W parach modyfikujemy podane na stronie przykłady: Klient:
Serwer:
Zadanie 2(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):
Zadanie 3(Multicast) Przerabiamy program z Zadania 2, aby działał na multicast. Protokół UDPUDP (User Datagram Protocol) jest protokołem transmisji danych, który ma następujące własności:
Zastosowania UDP
Na przykład synchronizacja plików między wieloma serwerami w jednej sieci. Jeden z serwerów wysyła te same dane do wszystkich podłączonych klientów.
W protokole TCP usługi, które pisaliśmy wymagały posiadania numeru IP serwera. Jest to całkiem uciążliwe w małych sieciach i sieciach ad-hoc. Chcielimbyśmy, by nasza sieć działała tak, że po podłączeniu nasz system może wykryć wszystkie usługi widoczne w sieci. Tego typu rozwiązania często implementuje się za pomocą UDP. Przykładem może być usługa NetBIOS, będąca częścią systemu sieciowego systemu Microsoft Windows (odpowiednik w systemach Linux nazywa się SAMBA).
Część sieci peer-to-peer korzysta z UDP zamiast z TCP, ponieważ nie potrzebują obsługi błędów (same posiadają sumy kontrolne poszczególnych plików, nie potrzebujemy zatem kontroli na poziomie protokołu).
Kiedy nasz system wysyla wiele krótkich wiadomości do wielu innych systemów. W takim przypadku okazuje się, że narzut na procedurę handshake TCP jest jest zbyt duży i całość działa mało wydajnie. Przykład: protokół ustalania czasu (Network Time Protocol) korzysta z UDP do komunikacji z klientami.
W przypadku streamingu mediów (audio, video), czy oprogramowania gier sieciowych ważne jest, to by opóźnienie przesłanych informacji było minimalne. BroadcastBroadcast jest w zasadzie funkcjonalnością protokołu IP, ale skoro nie można z niego skorzystać z poziomu TCP to mówimy o nim dopiero teraz. Załóżmy że mamy podsieć o masce: Maska podsieci (zapisana binarnie): 11111111 11111111 11111110 00000000 Adres komputera (zapisany binarnie): 11000010 00011101 10101110 01111011 Adres Broadcast (zapisany binarnie): 11000010 00011101 10101111 11111111
MulticastPrzesyłanie informacji od wszystkich użytkowników danej podsieci ma wiele zastosowań, ale ma poważne ograniczenia - wiadomości broadcast generalnie są wycinane przez routery, i nie nadają się do komunikacji poza siecią lokalną. Rozważmy przykładowo telewizję internetową: jeśli korzysta z wiadomości unicast (do jednego odbiorcy) ilość pakietów które wysyła rośnie liniowo z ilością odbiorców - mimo, że każdy odbiorca dostaje taki sam obraz (a w zasadzie: taką samą listę pakietów). By rozwiązać takie problemy stworzono wiadomości multicast, działają one w następujący sposób: Zdefiniowano podsieć
Komunikacja UDP w JavieUnicast/BroadcastKlasa konfiguracyjnaimport 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);
}
}
}
Serwerimport 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 receivedPacket
= new DatagramPacket( new byte[Config.BUFFER_SIZE], Config.BUFFER_SIZE);
datagramSocket.receive(receivedPacket);
int length = receivedPacket.getLength();
String message =
new String(receivedPacket.getData(), 0, length, "utf8");
// Port i host który wysłał nam zapytanie
InetAddress address = receivedPacket.getAddress();
int port = receivedPacket.getPort();
System.out.println(message);
Thread.sleep(1000); //To oczekiwanie nie jest potrzebne dla
// obsługi gniazda
DatagramPacket response
= new DatagramPacket(
byteResponse, byteResponse.length, address, port);
datagramSocket.send(response);
}
}
}
Ważniejsze miejsca programuPrzygotowanie do odbierania połączeń UDP na zadanym portcie: DatagramSocket datagramSocket = new DatagramSocket(9000); Stworzenie pakietu który będzie odbierał dane: DatagramPacket receivedPacket
= new DatagramPacket( new byte[BUFFER_SIZE], BUFFER_SIZE);
Odebranie pakietu: datagramSocket.receive(receivedPacket); 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-8. int length = receivedPacket.getLength();
String message =
new String(receivedPacket.getData(), 0, length, "utf8");
Wysłanie odpowiedzi: byte[] byteResponse = "OK".getBytes("utf8");
DatagramPacket response
= new DatagramPacket(
byteResponse, byteResponse.length, address, port);
Klientimport 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("localhost");
System.out.println(serverAddress);
DatagramSocket socket = new DatagramSocket(); //Otwarcie gniazda
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);
DatagramPacket recievePacket = new DatagramPacket( new byte[Config.BUFFER_SIZE], Config.BUFFER_SIZE);
socket.setSoTimeout(1010);
try{
socket.receive(recievePacket);
System.out.println("Serwer otrzymał wiadomość");
}catch (SocketTimeoutException ste){
System.out.println("Serwer nie odpowiedział, więc albo dostał wiadomość albo nie...");
}
}
}
Ważniejsze miejsca w programieWybieramy do jakiego adresu wysyłamy informacje: InetAddress serverAddress = InetAddress.getByName("localhost");
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(PORT);
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ź: Uwaga: Argument metody socket.setSoTimeout(1010); Odebranie danych: DatagramPacket receivedPacket = new DatagramPacket(new byte[Config.BUFFER_SIZE], Config.BUFFER_SIZE);
try{
socket.receive(receivedPacket);
System.out.println("Serwer otrzymał wiadomość");
}catch (SocketTimeoutException ste){
System.out.println("Serwer nie odpowiedział, więc albo dostał wiadomość albo nie...");
}
Zadanie 1(Unicast) W parach modyfikujemy powyższe przykłady: Klient:
Serwer:
Zadanie 2(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):
MulticastSerwerimport java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.MulticastSocket;
public class MulticastServer {
public static void main(String[] args) throws Exception{
byte[] responseBytes = "ACK".getBytes();
InetAddress group = Config.MULTICAST_ADDRESS;
MulticastSocket s = new MulticastSocket(Config.MULTICAST_PORT);
s.joinGroup(group);
try{
while (true){
DatagramPacket recv = new DatagramPacket(new byte[Config.BUFFER_SIZE], Config.BUFFER_SIZE);
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); // Ta linijka powoduje wstrzymanie wysyłania odpowiedzi przez
// jedną sekundę --- nie ma ona związku z obsługą UDP.
responseSocket.send(response);
}
}finally {
s.leaveGroup(group);
}
}
}
Ważniejsze miejsca programuStworzenie gniazda multicast - oraz dołączenie do grupy mulitcast InetAddress group = Config.MULTICAST_ADDRESS; MulticastSocket s = new MulticastSocket(Config.MULTICAST_PORT); s.joinGroup(group); Klientimport java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketTimeoutException;
public class MulticastClient {
public static void main(String[] args) throws Exception{
DatagramSocket s = new DatagramSocket();
byte[] message = "Test".getBytes("utf8");
DatagramPacket packet = new DatagramPacket(message, message.length);
packet.setPort(Config.PORT);
packet.setAddress(Config.MULTICAST_ADDRESS);
s.send(packet);
System.out.println("Wysłałem pakiet");
s.setSoTimeout(1000);
DatagramPacket response = new DatagramPacket(new byte[Config.BUFFER_SIZE], Config.BUFFER_SIZE);
try{
s.receive(response);
System.out.println("Odpowiedź: ");
System.out.print(new String(response.getData(), 0, response.getLength(), "utf8"));
}catch (SocketTimeoutException e){
System.out.println("Nie otrzymałem odpowiedzi");
}
}
}
Ważniejsze miejsca programuWysłanie pakietu na grupę multicast: DatagramPacket packet = new DatagramPacket(message, message.length); packet.setPort(Config.PORT); packet.setAddress(Config.MULTICAST_ADDRESS); s.send(packet); Ustawienie timeoutu na odowiedź: s.setSoTimeout(1000); Zadanie 3(Multicast) Przerabiamy program z Zadania 2, aby działał na multicast. Projekt nr 2Wybieramy (w parach) projekty z listy: http://www.if.pw.edu.pl/~lgraczyk/sk/html/pd2.html
Rozwiązania
| |||||||||||||||||||||||||||