Programowanie oparte na gniazdach (sockets)
Przetwarzanie adresów URL (HTTP)
TCP - połączeniowy, niezawodny, strumieniowy, kontrola kolejności
UDP - bezpołączeniowy, szybki, datagramowy, brak retransmisji
192.168.1.10, IPv6: 2001:db8::1 example.com → rozwiązywane na adresy IP przez DNSlocalhost, 127.0.0.1 - adres hosta lokalnegoInetAddress - reprezentuje adres IP i nazwę hosta. Kluczowe metody:
getByName(String host) - rozwiązywanie DNSgetByAddress(byte[] addr) - tworzenie z surowych bajtówgetLocalHost() - adres hosta lokalnegogetHostAddress() i getHostName()InetAddress local = InetAddress.getLocalHost(); System.out.println(local.getHostName()); System.out.println(local.getHostAddress()); InetAddress google = InetAddress.getByName("www.google.com"); System.out.println(google.getHostAddress());
ServerSocket) na konkretnym porcieaccept())Socket) i łączy się z serweremServerSocket tworzy gniazdo serwera TCP. Konstruktorzy:
ServerSocket(int port) - nasłuch na porcie (IOException jeśli port zajęty)ServerSocket(int port, int backlog) - nasłuch z określoną liczbą oczekujących połączeńServerSocket(int port, int backlog, InetAddress bindAddr) - nasłuch z określonym adresem (gdy serwer ma wiele interfejsów sieciowych)Kluczowe metody:
accept() - czeka na klienta i zwraca Socket (SocketTimeoutException jeśli timeout)bind(SocketAddress endpoint) - wiąże z adresem i portem (jeśli nie podano w konstruktorze)setSoTimeout(int timeout) - timeout dla accept()getLocalPort() - numer portu lokalnegoclose() - zamknięcie serwera (try-with-resources lub ręcznie)Socket tworzy gniazdo klienta TCP
Socket(String host, int port) - łączy z serwerem na adresie host i porcie portSocket(InetAddress host, int port) - łączy z serwerem na adresie host i porcie portSocket() - tworzy gniazdo bez połączeniaSocket(String host, int port, InetAddress localAddr, int localPort) - łączy z serwerem i wiąże z lokalnym adresem i portemMetody:
connect(SocketAddress host, int timeout) - łączy z serwerem (jeśli nie podano w konstruktorze)getInputStream() / getOutputStream() - strumienie do komunikacjigetInetAddress(), getPort(), getLocalPort(), getRemoteSocketAddress() - informacje o połączeniuclose() - zamyka gniazdoServerSocket server = new ServerSocket(5000); Socket client = server.accept(); // strumień wejściowy (tekstowy) do komunikacji z klientem BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream())); String line = in.readLine(); // strumień wyjściowy (tekstowy) do komunikacji z klientem PrintWriter out = new PrintWriter(client.getOutputStream(), true); out.println("ECHO: " + line);
try (Socket socket = new Socket("127.0.0.1", 5000); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) { out.println("ping"); String response = in.readLine(); System.out.println("Odpowiedz z serwera: " + response); }
UDP stosujemy, gdy nie jest potrzebna niezawodność i kolejność, a liczy się szybkość i niskie opóźnienia.
DatagramSocket tworzy gniazdo UDP:
DatagramSocket() - tworzy gniazdo i wiąże je z wolnym portemDatagramSocket(int port) - wiąże z konkretnym portemDatagramSocket(int port, InetAddress address) - wiąże z portem i adresemsend(DatagramPacket dp), receive(DatagramPacket dp) DatagramPacket - pakiet danych UDP:
DatagramPacket(byte[] barr, int length) - utworzenie pakietu do odbioru danychDatagramPacket(byte[] barr, int length, InetAddress address, int port) - utworzenie pakietu do wysłania danych do konkretnego adresu i portutry (DatagramSocket sender = new DatagramSocket()) { byte[] data = "hello udp".getBytes(StandardCharsets.UTF_8); DatagramPacket packet = new DatagramPacket( data, data.length, InetAddress.getByName("127.0.0.1"), 6000 ); sender.send(packet); }
try (DatagramSocket receiver = new DatagramSocket(6000)) { byte[] buffer = new byte[1024]; DatagramPacket packet = new DatagramPacket(buffer, buffer.length); receiver.receive(packet); String msg = new String(packet.getData(), 0, packet.getLength(), StandardCharsets.UTF_8); System.out.println("UDP: " + msg); }
URL url = new URL("https://example.com/api/users?page=1"); System.out.println(url.getProtocol()); // https System.out.println(url.getHost()); // example.com System.out.println(url.getPath()); // /api/users System.out.println(url.getQuery()); // page=1 System.out.println(url.getPort()); // -1 (domyślny port) System.out.println(url.getDefaultPort()); // 443 System.out.println(url.getFile()); // /api/users?page=1 System.out.println(url.getRef()); // null (część po #) System.out.println(url.getAuthority()); // example.com
URL url = new URL("https://api.github.com"); URLConnection conn = url.openConnection(); try (InputStream in = conn.getInputStream()) { String content = new String(in.readAllBytes(), StandardCharsets.UTF_8); System.out.println(content); }
getContent() - zwraca zawartość połączenia z URLgetContent(Class[] classes) - próbuje zwrócić zawartość połączenia jako jeden z typów podanych w parametrze classesgetContentEncoding() - zwraca zawartość nagłówka content-encodinggetContentLength() - zwraca zawartość nagłówka content-lengthgetContentType() - zwraca zawartość nagłówka content-typegetLastModified() - zwraca zawartość nagłówka last-modifiedgetExpiration() - zwraca zawartość nagłówka expiresgetInputStream() - zwraca strumień wejściowy z URL (pozwala na czytanie)getOutputStream() - zwraca strumień wyjściowy z URL (pozwala na wysyłanie)getURL() - zwraca adres URL do którego podłączony jest obiekt klasy URLConnectionHttpURLConnection to podklasa URLConnection, która dodaje funkcje specyficzne dla protokołu HTTP, takie jak obsługa metod HTTP, nagłówków, kodów statusu i innych aspektów komunikacji HTTP.
Metody:
setRequestMethod(String method) - GET, POST, itp.setRequestProperty(String key, String value) - nagłówkigetResponseCode() - kod statusu HTTPgetInputStream() - strumień odpowiedzi (dla 2xx)getContent() - zawartość odpowiedzigetErrorStream() - strumień błędu (dla 4xx/5xx)disconnect() - zamyka połączeniejava.net.http to nowoczesny klient HTTP wprowadzony w Javie 11, który oferuje bardziej elastyczne i wydajne API do pracy z protokołem HTTP/1.1 i HTTP/2
send), jak i asynchroniczna (sendAsync)builder()) do łatwego tworzenia żądań i konfiguracji klientaHttpClient client = HttpClient.newBuilder() .connectTimeout(Duration.ofSeconds(5)) .build(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.github.com")) .header("Accept", "application/json") .GET() .build(); HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.statusCode()); System.out.println(response.body());
com.sun.net.httpserver.HttpServerHttpServer server = HttpServer.create(new InetSocketAddress(8080), 0); server.createContext("/hello", exchange -> { String body = "{\"message\":\"hello\"}"; exchange.getResponseHeaders().add("Content-Type", "application/json; charset=utf-8"); exchange.sendResponseHeaders(200, body.getBytes(StandardCharsets.UTF_8).length); try (OutputStream os = exchange.getResponseBody()) { os.write(body.getBytes(StandardCharsets.UTF_8)); } }); server.start();
Stwórz prosty komunikator, który pozwala na bezpośrednią wymianę wiadomości tekstowych między dwiema aplikacjami korzystając z protokołu TCP.
localhost).Opcjonalnie:
Przykładowe rozwiązanie: