Jak stworzyć aplikację sieciową w Javie (ze zdjęciami)

Spisu treści:

Jak stworzyć aplikację sieciową w Javie (ze zdjęciami)
Jak stworzyć aplikację sieciową w Javie (ze zdjęciami)

Wideo: Jak stworzyć aplikację sieciową w Javie (ze zdjęciami)

Wideo: Jak stworzyć aplikację sieciową w Javie (ze zdjęciami)
Wideo: Jak zrobić zrzut ekranu smartfona (iOS oraz Android)? 2024, Kwiecień
Anonim

Pisanie kodu, który wykonuje się na określonym urządzeniu, jest bardzo satysfakcjonujące. Ale pisanie kodu, który jest wykonywany na kilku komunikujących się ze sobą urządzeniach, jest po prostu afirmacją życia. W tym artykule dowiesz się, jak łączyć się i wymieniać wiadomości przez sieć za pomocą protokołu kontroli transmisji (TCP).

W tym artykule skonfigurujesz aplikację, która połączy twój komputer z samym sobą i, w zasadzie, doprowadzi go do szaleństwa - porozmawia ze sobą. Dowiesz się również, jaka jest różnica między dwoma najczęściej używanymi strumieniami do pracy w sieci w Javie i jak one działają.

Strumienie danych i obiektów

Zanim zagłębimy się w kod, należy rozróżnić dwa strumienie użyte w artykule.

Strumienie danych

Strumienie danych przetwarzają prymitywne typy i ciągi danych. Dane przesyłane przez strumienie danych muszą być ręcznie serializowane i deserializowane, co utrudnia przesyłanie złożonych danych. Jednak strumienie danych mogą komunikować się z serwerami i klientami napisanymi w innych językach niż Java. Strumienie surowe są pod tym względem podobne do strumieni danych, ale strumienie danych zapewniają formatowanie danych w sposób niezależny od platformy, co jest korzystne, ponieważ obie strony będą w stanie odczytać przesłane dane.

Strumienie obiektów

Strumienie obiektów przetwarzają prymitywne typy danych i obiekty, które implementują

Możliwość serializacji

berło. Dane przesyłane strumieniami obiektów są automatycznie serializowane i deserializowane, co ułatwia przesyłanie złożonych danych. Jednak strumienie obiektów mogą komunikować się tylko z serwerami i klientami napisanymi w Javie. Także,

ObjectOutputStream

po inicjalizacji wysyła nagłówek do

Strumień wejściowy

drugiej strony, która po inicjalizacji blokuje wykonanie do momentu odebrania nagłówka.

Kroki

Utwórz aplikację sieciową w Javie Step1
Utwórz aplikację sieciową w Javie Step1

Krok 1. Stwórz klasę

Utwórz klasę i nazwij ją tak, jak chcesz. W tym artykule będzie się nazywać

Przykład aplikacji sieciowej

public class NetworkAppExample { }

Utwórz aplikację sieciową w Javie Step2
Utwórz aplikację sieciową w Javie Step2

Krok 2. Utwórz główną metodę

Utwórz główną metodę i zadeklaruj, że może zgłaszać wyjątki

Wyjątek

typ i dowolna jego podklasa - wszystkie wyjątki. Jest to uważane za złą praktykę, ale jest dopuszczalne w przypadku kadłubków.

public class NetworkAppExample { public static void main(String args) wyrzuca wyjątek { } }

Utwórz aplikację sieciową w Javie Step3
Utwórz aplikację sieciową w Javie Step3

Krok 3. Zadeklaruj adres serwera

W tym przykładzie zostanie użyty adres lokalnego hosta i dowolny numer portu. Numer portu musi mieścić się w zakresie od 0 do 65535 (włącznie). Jednak numery portów, których należy unikać, mieszczą się w zakresie od 0 do 1023 (włącznie), ponieważ są to zastrzeżone porty systemowe.

public class NetworkAppExample { public static void main(String args) wyrzuca wyjątek { String host = "localhost"; port wewnętrzny = 10430; } }

Utwórz aplikację sieciową w Javie Step4
Utwórz aplikację sieciową w Javie Step4

Krok 4. Utwórz serwer

Serwer jest powiązany z adresem i portem i nasłuchuje połączeń przychodzących. W Javie

Gniazdo serwera

reprezentuje punkt końcowy po stronie serwera, a jego funkcją jest przyjmowanie nowych połączeń.

Gniazdo serwera

nie ma strumieni do odczytu i wysyłania danych, ponieważ nie reprezentuje połączenia między serwerem a klientem.

import java.net. InetAddress; import java.net. ServerSocket; public class NetworkAppExample { public static void main(String args) wyrzuca wyjątek { String host = "localhost"; port wewnętrzny = 10430; ServerSocket server = new ServerSocket(port, 50, InetAddress.getByName(host)); } }

Utwórz aplikację sieciową w Javie Step5
Utwórz aplikację sieciową w Javie Step5

Krok 5. Inicjacja serwera dziennika

W celu rejestrowania wydrukuj do konsoli, że serwer został uruchomiony.

import java.net. InetAddress; import java.net. ServerSocket; public class NetworkAppExample { public static void main(String args) wyrzuca wyjątek { String host = "localhost"; port wewnętrzny = 10430; ServerSocket server = new ServerSocket(port, 50, InetAddress.getByName(host)); System.out.println("Serwer uruchomiony."); } }

Utwórz aplikację sieciową w Javie Step6
Utwórz aplikację sieciową w Javie Step6

Krok 6. Utwórz klienta

Klient jest powiązany z adresem i portem serwera i nasłuchuje pakietów (wiadomości) po nawiązaniu połączenia. W Javie

Gniazdo elektryczne

reprezentuje punkt końcowy po stronie klienta podłączony do serwera lub połączenie (z serwera) z klientem i służy do komunikacji ze stroną po drugiej stronie.

importowanie adresu java.net. Inet; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample { public static void main(String args) wyrzuca wyjątek { String host = "localhost"; port wewnętrzny = 10430; ServerSocket server = new ServerSocket(port, 50, InetAddress.getByName(host)); System.out.println("Serwer uruchomiony."); Klient gniazda = nowy Socket(host, port); } }

Utwórz aplikację sieciową w Javie Step7
Utwórz aplikację sieciową w Javie Step7

Krok 7. Zaloguj próbę połączenia

W celu rejestrowania wydrukuj na konsoli informację, że podjęto próbę połączenia.

importowanie adresu java.net. Inet; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample { public static void main(String args) wyrzuca wyjątek { String host = "localhost"; port wewnętrzny = 10430; ServerSocket server = new ServerSocket(port, 50, InetAddress.getByName(host)); System.out.println("Serwer uruchomiony."); Klient gniazda = nowy Socket(host, port); System.out.println("Łączenie z serwerem…"); } }

Utwórz aplikację sieciową w Javie Step8
Utwórz aplikację sieciową w Javie Step8

Krok 8. Nawiąż połączenie

Klienci nigdy się nie połączą, chyba że serwer nasłuchuje i nie zaakceptuje, innymi słowy, nawiąże połączenia. W Javie połączenia są nawiązywane za pomocą

zaakceptować()

metoda

Gniazdo serwera

klasa. Metoda zablokuje wykonanie do momentu nawiązania połączenia przez klienta.

importowanie adresu java.net. Inet; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample { public static void main(String args) wyrzuca wyjątek { String host = "localhost"; port wewnętrzny = 10430; ServerSocket server = new ServerSocket(port, 50, InetAddress.getByName(host)); System.out.println("Serwer uruchomiony."); Klient gniazda = nowy Socket(host, port); System.out.println("Łączenie z serwerem…"); Połączenie z gniazdem = server.accept(); } }

Utwórz aplikację sieciową w Javie Step9
Utwórz aplikację sieciową w Javie Step9

Krok 9. Zaloguj nawiązane połączenie

W celu rejestrowania wydrukuj na konsoli informację, że zostało ustanowione połączenie między serwerem a klientem.

importowanie adresu java.net. Inet; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample { public static void main(String args) wyrzuca wyjątek { String host = "localhost"; port wewnętrzny = 10430; ServerSocket server = new ServerSocket(port, 50, InetAddress.getByName(host)); System.out.println("Serwer uruchomiony."); Klient gniazda = nowy Socket(host, port); System.out.println("Łączenie z serwerem…"); Połączenie z gniazdem = server.accept(); System.out.println("Połączenie nawiązane."); } }

Utwórz aplikację sieciową w Javie Step10
Utwórz aplikację sieciową w Javie Step10

Krok 10. Przygotuj strumienie komunikacji

Komunikacja odbywa się za pośrednictwem strumieni i, w tej aplikacji, nieprzetworzone strumienie (połączenia z) serwera (do klienta) i klienta muszą być połączone ze strumieniami danych lub obiektów. Pamiętaj, że obie strony muszą używać tego samego typu strumienia.

  • Strumienie danych

    import java.io. DataInputStream; import java.io. DataOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample { public static void main(String args) wyrzuca wyjątek { String host = "localhost"; port wewnętrzny = 10430; ServerSocket server = new ServerSocket(port, 50, InetAddress.getByName(host)); System.out.println("Serwer uruchomiony."); Klient gniazda = nowy Socket(host, port); System.out.println("Łączenie z serwerem…"); Połączenie z gniazdem = server.accept(); System.out.println("Połączenie nawiązane."); DataOutputStream clientOut = new DataOutputStream(client.getOutputStream()); DataInputStream clientIn = new DataInputStream(client.getInputStream()); DataOutputStream serverOut = new DataOutputStream(connection.getOutputStream()); DataInputStream serverIn = new DataInputStream(connection.getInputStream()); } }

  • Strumienie obiektów

    Gdy używanych jest wiele strumieni obiektów, strumienie wejściowe muszą być inicjowane w tej samej kolejności co strumienie wyjściowe, ponieważ

    ObjectOutputStream

    wysyła nagłówek do drugiej strony i

    ObjectInputStream

    blokuje wykonanie, dopóki nie odczyta nagłówka.

    import java.io. ObjectInputStream; import java.io. ObjectOutputStream; importowanie adresu java.net. Inet; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample { public static void main(String args) wyrzuca wyjątek { String host = "localhost"; port wewnętrzny = 10430; ServerSocket server = new ServerSocket(port, 50, InetAddress.getByName(host)); System.out.println("Serwer uruchomiony."); Klient gniazda = nowy Socket(host, port); System.out.println("Łączenie z serwerem…"); Połączenie z gniazdem = server.accept(); System.out.println("Połączenie nawiązane."); ObjectOutputStream clientOut = new ObjectOutputStream(client.getOutputStream()); ObjectOutputStream serverOut = new ObjectOutputStream(connection.getOutputStream()); ObjectInputStream clientIn = new ObjectInputStream(client.getInputStream()); ObjectInputStream serverIn = new ObjectInputStream(connection.getInputStream()); } }

    Kolejność określona w powyższym kodzie może być łatwiejsza do zapamiętania - najpierw zainicjuj strumienie wyjściowe, a następnie strumienie wejściowe w tej samej kolejności. Jednak inna kolejność inicjalizacji strumieni obiektów jest następująca:

    ObjectOutputStream clientOut = new ObjectOutputStream(client.getOutputStream()); ObjectInputStream serverIn = new ObjectInputStream(connection.getInputStream()); ObjectOutputStream serverOut = new ObjectOutputStream(connection.getOutputStream()); ObjectInputStream clientIn = new ObjectInputStream(client.getInputStream());

Utwórz aplikację sieciową w Javie Step11
Utwórz aplikację sieciową w Javie Step11

Krok 11. Zaloguj się, że komunikacja jest gotowa

W celu rejestrowania wydrukuj na konsoli informację, że komunikacja jest gotowa.

// pominięto kod import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample { public static void main(String args) wyrzuca wyjątek { String host = "localhost"; port wewnętrzny = 10430; ServerSocket server = new ServerSocket(port, 50, InetAddress.getByName(host)); System.out.println("Serwer uruchomiony."); Klient gniazda = nowy Socket(host, port); System.out.println("Łączenie z serwerem…"); Połączenie z gniazdem = server.accept(); System.out.println("Połączenie nawiązane."); // kod pominięty System.out.println("Komunikacja jest gotowa."); } }

Utwórz aplikację sieciową w Javie Step12
Utwórz aplikację sieciową w Javie Step12

Krok 12. Utwórz wiadomość

W tej aplikacji

Witaj świecie

tekst zostanie wysłany na serwer jako

bajt

lub

Strunowy

. Zadeklaruj zmienną typu, który zależy od używanego strumienia. Posługiwać się

bajt

dla strumieni danych i

Strunowy

dla strumieni obiektów.

  • Strumienie danych

    Korzystając ze strumieni danych, serializacja odbywa się poprzez konwersję obiektów na prymitywne typy danych lub a

    Strunowy

    . W tym przypadku,

    Strunowy

    jest konwertowany na

    bajt

    zamiast pisać używając

    writeBytes()

    metoda, aby pokazać, jak byłoby to zrobione z innymi obiektami, takimi jak obrazy lub inne pliki.

    import java.io. DataInputStream; import java.io. DataOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample { public static void main(String args) wyrzuca wyjątek { String host = "localhost"; port wewnętrzny = 10430; ServerSocket server = new ServerSocket(port, 50, InetAddress.getByName(host)); System.out.println("Serwer uruchomiony."); Klient gniazda = nowy Socket(host, port); System.out.println("Łączenie z serwerem…"); Połączenie z gniazdem = server.accept(); System.out.println("Połączenie nawiązane."); DataOutputStream clientOut = new DataOutputStream(client.getOutputStream()); DataInputStream clientIn = new DataInputStream(client.getInputStream()); DataOutputStream serverOut = new DataOutputStream(connection.getOutputStream()); DataInputStream serverIn = new DataInputStream(connection.getInputStream()); System.out.println("Komunikacja jest gotowa."); byte messageOut = "Witaj świecie".getBytes(); } }

  • Strumienie obiektów

    import java.io. ObjectInputStream; import java.io. ObjectOutputStream; importowanie adresu java.net. Inet; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample { public static void main(String args) wyrzuca wyjątek { String host = "localhost"; port wewnętrzny = 10430; ServerSocket server = new ServerSocket(port, 50, InetAddress.getByName(host)); System.out.println("Serwer uruchomiony."); Klient gniazda = nowy Socket(host, port); System.out.println("Łączenie z serwerem…"); Połączenie z gniazdem = server.accept(); System.out.println("Połączenie nawiązane."); ObjectOutputStream clientOut = new ObjectOutputStream(client.getOutputStream()); ObjectOutputStream serverOut = new ObjectOutputStream(connection.getOutputStream()); ObjectInputStream clientIn = new ObjectInputStream(client.getInputStream()); ObjectInputStream serverIn = new ObjectInputStream(connection.getInputStream()); System.out.println("Komunikacja jest gotowa."); String messageOut = "Witaj świecie"; } }

Utwórz aplikację sieciową w Javie Step13
Utwórz aplikację sieciową w Javie Step13

Krok 13. Wyślij wiadomość

Zapisz dane w strumieniu wyjściowym i opróżnij strumień, aby upewnić się, że dane zostały zapisane w całości.

  • Strumienie danych

    Najpierw należy przesłać długość wiadomości, aby druga strona wiedziała, ile bajtów musi odczytać. Po wysłaniu długości jako podstawowego typu liczby całkowitej można wysłać bajty.

    import java.io. DataInputStream; import java.io. DataOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample { public static void main(String args) wyrzuca wyjątek { String host = "localhost"; port wewnętrzny = 10430; ServerSocket server = new ServerSocket(port, 50, InetAddress.getByName(host)); System.out.println("Serwer uruchomiony."); Klient gniazda = nowy Socket(host, port); System.out.println("Łączenie z serwerem…"); Połączenie z gniazdem = server.accept(); System.out.println("Połączenie nawiązane."); DataOutputStream clientOut = new DataOutputStream(client.getOutputStream()); DataInputStream clientIn = new DataInputStream(client.getInputStream()); DataOutputStream serverOut = new DataOutputStream(connection.getOutputStream()); DataInputStream serverIn = new DataInputStream(connection.getInputStream()); System.out.println("Komunikacja jest gotowa."); byte messageOut = "Witaj świecie".getBytes(); klientOut.writeInt(messageOut.length); klientOut.write(messageOut); klientOut.flush(); } }

  • Strumienie obiektów

    import java.io. ObjectInputStream; import java.io. ObjectOutputStream; importowanie adresu java.net. Inet; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample { public static void main(String args) wyrzuca wyjątek { String host = "localhost"; port wewnętrzny = 10430; ServerSocket server = new ServerSocket(port, 50, InetAddress.getByName(host)); System.out.println("Serwer uruchomiony."); Klient gniazda = nowy Socket(host, port); System.out.println("Łączenie z serwerem…"); Połączenie z gniazdem = server.accept(); System.out.println("Połączenie nawiązane."); ObjectOutputStream clientOut = new ObjectOutputStream(client.getOutputStream()); ObjectOutputStream serverOut = new ObjectOutputStream(connection.getOutputStream()); ObjectInputStream clientIn = new ObjectInputStream(client.getInputStream()); ObjectInputStream serverIn = new ObjectInputStream(connection.getInputStream()); System.out.println("Komunikacja jest gotowa."); String messageOut = "Witaj świecie"; klientOut.writeObject(messageOut); klientOut.flush(); } }

Utwórz aplikację sieciową w Javie Step14
Utwórz aplikację sieciową w Javie Step14

Krok 14. Zaloguj wysłaną wiadomość

W celu rejestrowania wydrukuj w konsoli wiadomość, która została wysłana.

  • Strumienie danych

    import java.io. DataInputStream; import java.io. DataOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample { public static void main(String args) wyrzuca wyjątek { String host = "localhost"; port wewnętrzny = 10430; ServerSocket server = new ServerSocket(port, 50, InetAddress.getByName(host)); System.out.println("Serwer uruchomiony."); Klient gniazda = nowy Socket(host, port); System.out.println("Łączenie z serwerem…"); Połączenie z gniazdem = server.accept(); System.out.println("Połączenie nawiązane."); DataOutputStream clientOut = new DataOutputStream(client.getOutputStream()); DataInputStream clientIn = new DataInputStream(client.getInputStream()); DataOutputStream serverOut = new DataOutputStream(connection.getOutputStream()); DataInputStream serverIn = new DataInputStream(connection.getInputStream()); System.out.println("Komunikacja jest gotowa."); byte messageOut = "Witaj świecie".getBytes(); klientOut.writeInt(messageOut.length); klientOut.write(messageOut); klientOut.flush(); System.out.println("Wiadomość wysłana do serwera: " + nowy String(messageOut)); } }

  • Strumienie obiektów

    import java.io. ObjectInputStream; import java.io. ObjectOutputStream; importowanie adresu java.net. Inet; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample { public static void main(String args) wyrzuca wyjątek { String host = "localhost"; port wewnętrzny = 10430; ServerSocket server = new ServerSocket(port, 50, InetAddress.getByName(host)); System.out.println("Serwer uruchomiony."); Klient gniazda = nowy Socket(host, port); System.out.println("Łączenie z serwerem…"); Połączenie z gniazdem = server.accept(); System.out.println("Połączenie nawiązane."); ObjectOutputStream clientOut = new ObjectOutputStream(client.getOutputStream()); ObjectOutputStream serverOut = new ObjectOutputStream(connection.getOutputStream()); ObjectInputStream clientIn = new ObjectInputStream(client.getInputStream()); ObjectInputStream serverIn = new ObjectInputStream(connection.getInputStream()); System.out.println("Komunikacja jest gotowa."); String messageOut = "Witaj świecie"; klientOut.writeObject(messageOut); klientOut.flush(); System.out.println("Wiadomość wysłana do serwera: " + messageOut); } }

Utwórz aplikację sieciową w Javie Step15
Utwórz aplikację sieciową w Javie Step15

Krok 15. Przeczytaj wiadomość

Odczytaj dane ze strumienia wejściowego i przekonwertuj je. Ponieważ dokładnie znamy rodzaj przesyłanych danych, albo utworzymy

Strunowy

z

bajt

lub obsada

Obiekt

do

Strunowy

bez sprawdzania, w zależności od używanego strumienia.

  • Strumienie danych

    Ponieważ długość została wysłana jako pierwsza, a bajty później, odczyt należy wykonać w tej samej kolejności. Jeśli długość wynosi zero, nie ma nic do odczytania. Obiekt jest deserializowany, gdy bajty są konwertowane z powrotem na instancję, w tym przypadku

    Strunowy

    import java.io. DataInputStream; import java.io. DataOutputStream; importowanie adresu java.net. Inet; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample { public static void main(String args) wyrzuca wyjątek { String host = "localhost"; port wewnętrzny = 10430; ServerSocket server = new ServerSocket(port, 50, InetAddress.getByName(host)); System.out.println("Serwer uruchomiony."); Klient gniazda = nowy Socket(host, port); System.out.println("Łączenie z serwerem…"); Połączenie z gniazdem = server.accept(); System.out.println("Połączenie nawiązane."); DataOutputStream clientOut = new DataOutputStream(client.getOutputStream()); DataInputStream clientIn = new DataInputStream(client.getInputStream()); DataOutputStream serverOut = new DataOutputStream(connection.getOutputStream()); DataInputStream serverIn = new DataInputStream(connection.getInputStream()); System.out.println("Komunikacja jest gotowa."); byte messageOut = "Witaj świecie".getBytes(); klientOut.writeInt(messageOut.length); klientOut.write(messageOut); klientOut.flush(); System.out.println("Wiadomość wysłana do serwera: " + nowy String(messageOut)); int length = serverIn.readInt(); if (długość > 0) { bajt wiadomośćIn = nowy bajt[długość]; serverIn.readFully(messageIn, 0, messageIn.length); } } }

  • Strumienie obiektów

    import java.io. ObjectInputStream; import java.io. ObjectOutputStream; importowanie adresu java.net. Inet; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample { public static void main(String args) wyrzuca wyjątek { String host = "localhost"; port wewnętrzny = 10430; ServerSocket server = new ServerSocket(port, 50, InetAddress.getByName(host)); System.out.println("Serwer uruchomiony."); Klient gniazda = nowy Socket(host, port); System.out.println("Łączenie z serwerem…"); Połączenie z gniazdem = server.accept(); System.out.println("Połączenie nawiązane."); ObjectOutputStream clientOut = new ObjectOutputStream(client.getOutputStream()); ObjectOutputStream serverOut = new ObjectOutputStream(connection.getOutputStream()); ObjectInputStream clientIn = new ObjectInputStream(client.getInputStream()); ObjectInputStream serverIn = new ObjectInputStream(connection.getInputStream()); System.out.println("Komunikacja jest gotowa."); String messageOut = "Witaj świecie"; klientOut.writeObject(messageOut); klientOut.flush(); System.out.println("Wiadomość wysłana do serwera: " + messageOut); String messageIn = (String) serverIn.readObject(); } }

Utwórz aplikację sieciową w Javie Step16
Utwórz aplikację sieciową w Javie Step16

Krok 16. Zaloguj przeczytaną wiadomość

W celach rejestrowania wydrukuj w konsoli wiadomość, która została odebrana i wydrukuj jej zawartość.

  • Strumienie danych

    import java.io. DataInputStream; import java.io. DataOutputStream; importowanie adresu java.net. Inet; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample { public static void main(String args) wyrzuca wyjątek { String host = "localhost"; port wewnętrzny = 10430; ServerSocket server = new ServerSocket(port, 50, InetAddress.getByName(host)); System.out.println("Serwer uruchomiony."); Klient gniazda = nowy Socket(host, port); System.out.println("Łączenie z serwerem…"); Połączenie z gniazdem = server.accept(); System.out.println("Połączenie nawiązane."); DataOutputStream clientOut = new DataOutputStream(client.getOutputStream()); DataInputStream clientIn = new DataInputStream(client.getInputStream()); DataOutputStream serverOut = new DataOutputStream(connection.getOutputStream()); DataInputStream serverIn = new DataInputStream(connection.getInputStream()); System.out.println("Komunikacja jest gotowa."); byte messageOut = "Witaj świecie".getBytes(); klientOut.writeInt(messageOut.length); klientOut.write(messageOut); klientOut.flush(); System.out.println("Wiadomość wysłana do serwera: " + nowy String(messageOut)); int length = serverIn.readInt(); if (długość > 0) { bajt wiadomośćIn = nowy bajt[długość]; serverIn.readFully(messageIn, 0, messageIn.length); System.out.println("Wiadomość odebrana od klienta: " + nowy String(messageIn)); } } }

  • Strumienie obiektów

    import java.io. ObjectInputStream; import java.io. ObjectOutputStream; importowanie adresu java.net. Inet; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample { public static void main(String args) wyrzuca wyjątek { String host = "localhost"; port wewnętrzny = 10430; ServerSocket server = new ServerSocket(port, 50, InetAddress.getByName(host)); System.out.println("Serwer uruchomiony."); Klient gniazda = nowy Socket(host, port); System.out.println("Łączenie z serwerem…"); Połączenie z gniazdem = server.accept(); System.out.println("Połączenie nawiązane."); ObjectOutputStream clientOut = new ObjectOutputStream(client.getOutputStream()); ObjectOutputStream serverOut = new ObjectOutputStream(connection.getOutputStream()); ObjectInputStream clientIn = new ObjectInputStream(client.getInputStream()); ObjectInputStream serverIn = new ObjectInputStream(connection.getInputStream()); System.out.println("Komunikacja jest gotowa."); String messageOut = "Witaj świecie"; klientOut.writeObject(messageOut); klientOut.flush(); System.out.println("Wiadomość wysłana do serwera: " + messageOut); String messageIn = (String) serverIn.readObject(); System.out.println("Wiadomość odebrana od klienta: " + messageIn); } }

Utwórz aplikację sieciową w Javie Step17
Utwórz aplikację sieciową w Javie Step17

Krok 17. Rozłącz połączenia

Połączenie jest rozłączane, gdy jedna ze stron zamyka swoje strumienie. W Javie zamknięcie strumienia wyjściowego powoduje również zamknięcie powiązanego gniazda i strumienia wejściowego. Gdy strona po drugiej stronie dowie się, że połączenie nie działa, musi również zamknąć strumień wyjściowy, aby zapobiec wyciekom pamięci.

// pominięto kod import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample { public static void main(String args) wyrzuca wyjątek { String host = "localhost"; port wewnętrzny = 10430; ServerSocket server = new ServerSocket(port, 50, InetAddress.getByName(host)); System.out.println("Serwer uruchomiony."); Klient gniazda = nowy Socket(host, port); System.out.println("Łączenie z serwerem…"); Połączenie z gniazdem = server.accept(); System.out.println("Połączenie nawiązane."); // kod pominięty System.out.println("Komunikacja jest gotowa."); // pominięto kod clientOut.close(); serwerOut.zamknij(); } }

Utwórz aplikację sieciową w Javie Step18 V2
Utwórz aplikację sieciową w Javie Step18 V2

Krok 18. Rozłączenie dziennika

Na potrzeby rejestrowania połączenia drukowania do konsoli zostały rozłączone.

// pominięto kod import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample { public static void main(String args) wyrzuca wyjątek { String host = "localhost"; port wewnętrzny = 10430; ServerSocket server = new ServerSocket(port, 50, InetAddress.getByName(host)); System.out.println("Serwer uruchomiony."); Klient gniazda = nowy Socket(host, port); System.out.println("Łączenie z serwerem…"); Połączenie z gniazdem = server.accept(); System.out.println("Połączenie nawiązane."); // kod pominięty System.out.println("Komunikacja jest gotowa."); // pominięto kod clientOut.close(); serwerOut.zamknij(); System.out.println("Połączenia zamknięte."); } }

Utwórz aplikację sieciową w Javie Step19
Utwórz aplikację sieciową w Javie Step19

Krok 19. Zakończ serwer

Połączenia są rozłączone, ale serwer nadal działa. Jak

Gniazdo serwera

nie jest powiązany z żadnym strumieniem, należy go jawnie zamknąć przez wywołanie

blisko()

metoda.

// pominięto kod import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample { public static void main(String args) wyrzuca wyjątek { String host = "localhost"; port wewnętrzny = 10430; ServerSocket server = new ServerSocket(port, 50, InetAddress.getByName(host)); System.out.println("Serwer uruchomiony."); Klient gniazda = nowy Socket(host, port); System.out.println("Łączenie z serwerem…"); Połączenie z gniazdem = server.accept(); System.out.println("Połączenie nawiązane."); // kod pominięty System.out.println("Komunikacja jest gotowa."); // pominięto kod clientOut.close(); serwerOut.zamknij(); System.out.println("Połączenia zamknięte."); serwer.zamknij(); } }

Utwórz aplikację sieciową w Javie Step20
Utwórz aplikację sieciową w Javie Step20

Krok 20. Zakończenie serwera dziennika

Na potrzeby rejestrowania drukowanie na serwerze konsoli zostało zakończone.

// pominięto kod import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; public class NetworkAppExample { public static void main(String args) wyrzuca wyjątek { String host = "localhost"; port wewnętrzny = 10430; ServerSocket server = new ServerSocket(port, 50, InetAddress.getByName(host)); System.out.println("Serwer uruchomiony."); Klient gniazda = nowy Socket(host, port); System.out.println("Łączenie z serwerem…"); Połączenie z gniazdem = server.accept(); System.out.println("Połączenie nawiązane."); // kod pominięty System.out.println("Komunikacja jest gotowa."); // pominięto kod clientOut.close(); serwerOut.zamknij(); System.out.println("Połączenia zamknięte."); serwer.zamknij(); System.out.println("Zakończono pracę serwera."); } }

Utwórz aplikację sieciową w Javie Step21
Utwórz aplikację sieciową w Javie Step21

Krok 21. Skompiluj i uruchom

Logowanie pozwoliło nam dowiedzieć się, czy aplikacja się powiodła, czy nie. Oczekiwany wynik:

Serwer uruchomiony. Trwa łączenie z serwerem… Nawiązano połączenie. Komunikacja jest gotowa. Wiadomość wysłana do serwera: Hello World Wiadomość odebrana od klienta: Hello World Połączenia zamknięte. Serwer zakończony.

W przypadku, gdy Twój wynik nie jest podobny do powyższego, co jest mało prawdopodobne, istnieje kilka rozwiązań:

  • Jeśli wyjście zatrzymuje się na linii

    Połączenie nawiązane.

    i strumienie obiektów są używane, opróżnij każdy

    ObjectOutputStream

  • natychmiast po inicjalizacji, ponieważ z jakiegoś powodu nagłówki nie zostały wysłane.
  • Jeśli wydruk zostanie wydrukowany

    java.net. BindException: adres już używany

  • wybierz inny numer portu, ponieważ podany jest już używany.

Porady

  • Połączenie z serwerem w innej sieci odbywa się poprzez połączenie z zewnętrznym adresem IP urządzenia z uruchomionym serwerem, który ma przekierowany port.
  • Połączenie z serwerem w tej samej sieci odbywa się poprzez połączenie z prywatnym adresem IP urządzenia z uruchomionym serwerem lub przekierowanie portu i połączenie z zewnętrznym adresem IP urządzenia.
  • Istnieją programy, takie jak Hamachi, które umożliwiają połączenie z serwerem w innej sieci bez przekazywania portu, ale wymagają instalacji oprogramowania na obu urządzeniach.

Przykłady

Aplikacje sieciowe korzystające z blokowania wejścia/wyjścia muszą używać wątków. Poniższe przykłady pokazują minimalistyczną implementację serwera i klienta z wątkami. Kod sieciowy jest zasadniczo taki sam jak w artykule, z wyjątkiem niektórych fragmentów kodu, które zostały zsynchronizowane, przeniesione do wątków i obsługiwane są wyjątki.

Server.java

import java.io. IOException; importowanie adresu java.net. Inet; import java.net. ServerSocket; import java.net. SocketException; import java.net. UnknownHostException; import java.util. ArrayList; importować java.util. Collections; import java.util. Lista; /** * Klasa {@code Server} reprezentuje punkt końcowy serwera w sieci. {@code Server} po przypisaniu do określonego adresu IP* i portu nawiązuje połączenia z klientami i jest w stanie komunikować się z nimi lub rozłączać ich. *

* Ta klasa jest bezpieczna wątkowo. * * @wersja 1.0 * @see Klient * @see Połączenie */ public class Serwer implementuje Runnable { private ServerSocket server; Lista prywatna znajomości; prywatny wątek wątku; private final Object connectionLock = new Object(); /** * Konstruuje {@code Server}, który współdziała z klientami na określonej nazwie hosta i porcie z określoną * żądaną maksymalną długością kolejki przychodzących klientów. * * @param host Adres hosta do użycia. * @param port Numer portu do użycia. * @param backlog Żądana maksymalna długość kolejki przychodzących klientów. * @throws NetworkException Jeśli wystąpi błąd podczas uruchamiania serwera. */ public Server(String host, int port, int backlog) throws NetworkException { try { server = new ServerSocket(port, backlog, InetAddress.getByName(host)); } catch (UnknownHostException e) { throw new NetworkException("Nazwa hosta nie może zostać rozwiązana: " + host, e); } catch (IllegalArgumentException e) { throw new NetworkException("Numer portu musi być z zakresu od 0 do 65535 (włącznie): " + port); } catch (IOException e) { throw new NetworkException("Nie można uruchomić serwera.", e); } połączenia = Collections.synchronizedList(new ArrayList()); wątek = nowy wątek(to); wątek.start(); } /** * Konstruuje {@code Server}, który współdziała z klientami na określonej nazwie hosta i porcie. * * @param host Adres hosta do powiązania. * @param port Numer portu do powiązania. * @throws NetworkException Jeśli wystąpią błędy podczas uruchamiania serwera. */ public Server(String host, int port) wyrzuca NetworkException { this(host, port, 50); } /** * Nasłuchuje, akceptuje i rejestruje połączenia przychodzące od klientów. */ @Override public void run() { while (!server.isClosed()) { try { connections.add(new Connection(server.accept())); } catch (SocketException e) { if (!e.getMessage().equals("Gniazdo zamknięte")) { e.printStackTrace(); } } catch (NetworkException | IOException e) { e.printStackTrace(); } } } /** * Wysyła dane do wszystkich zarejestrowanych klientów. * * @param data Dane do wysłania. * @throws IllegalStateException W przypadku próby zapisu danych, gdy serwer jest w trybie offline. * @throws IllegalArgumentException Jeśli dane do wysłania mają wartość NULL. */ public void broadcast(Object data) { if (server.isClosed()) { throw new IllegalStateException("Dane nie zostały wysłane, serwer jest w trybie offline."); } if (data == null) { throw new IllegalArgumentException("dane null"); } synced (connectionsLock) { for (Połączenie połączenia: połączenia) { try { connection.send(data); System.out.println("Dane wysłane do klienta pomyślnie."); } catch (NetworkException e) { e.printStackTrace(); } } } } /** * Wysyła wiadomość o rozłączeniu i rozłącza określonego klienta. * * @param connection Klient do rozłączenia. * @throws NetworkException Jeśli wystąpi błąd podczas zamykania połączenia. */ public void odłączenie(połączenie) zgłasza NetworkException { if (connections.remove(połączenie)) { connection.close(); } } /** * Wysyła wiadomość o rozłączeniu do wszystkich klientów, rozłącza ich i kończy działanie serwera. */ public void close() wyrzuca NetworkException { syncd (connectionsLock) { for (Connection connection: connections) { try { connection.close(); } catch (NetworkException e) { e.printStackTrace(); } } } połączenia.clear(); spróbuj { serwer.zamknij(); } catch (IOException e) { throw new NetworkException("Błąd podczas zamykania serwera."); } wreszcie { thread.interrupt(); } } /** * Zwraca czy serwer jest w trybie online. * * @return Prawda, jeśli serwer jest w trybie online. Fałsz, inaczej. */ public boolean isOnline() { return !server.isClosed(); } /** * Zwraca tablicę zarejestrowanych klientów. */ public Connection getConnections() { synced (connectionsLock) { return connections.toArray(new Connection[connections.size()]); } } }

Klient.java

import java.io. IOException; import java.net. Socket; import java.net. UnknownHostException; /** * Klasa {@code Client} reprezentuje punkt końcowy klienta w sieci. {@code Client} po połączeniu z określonym * serwerem gwarantuje, że będzie mógł komunikować się tylko z tym serwerem. To, czy inni klienci otrzymają dane *, zależy od implementacji serwera. *

* Ta klasa jest bezpieczna wątkowo. * * @wersja 1.0 * @see Serwer * @see Połączenie */ public class Klient { private Połączenie połączenie; /** * Konstruuje {@code Client} połączonego z serwerem na określonym hoście i porcie. * * @param host Adres hosta do powiązania. * @param port Numer portu do powiązania. * @throws NetworkException Jeśli wystąpi błąd podczas uruchamiania serwera. */ public Client(String host, int port) wyrzuca NetworkException { try { connection = new Connection(new Socket(host, port)); } catch (UnknownHostException e) { throw new NetworkException("Nazwa hosta nie może zostać rozwiązana: " + host, e); } catch (IllegalArgumentException e) { throw new NetworkException("Numer portu musi być z zakresu od 0 do 65535 (włącznie): " + port); } catch (IOException e) { throw new NetworkException("Nie można uruchomić serwera.", e); } } /** * Wysyła dane do drugiej strony. * * @param data Dane do wysłania. * @throws NetworkException Jeśli zapis do strumienia wyjściowego nie powiedzie się. * @throws IllegalStateException W przypadku próby zapisu danych po zamknięciu połączenia. * @throws IllegalArgumentException Jeśli dane do wysłania mają wartość NULL. * @throws UnsupportedOperationException W przypadku próby wysłania nieobsługiwanego typu danych. */ public void send(Object data) wyrzuca NetworkException { connection.send(data); } /** * Wysyła wiadomość o rozłączeniu i zamyka połączenie z serwerem. */ public void close() zgłasza NetworkException { connection.close(); } /** * Zwraca czy klient jest połączony z serwerem. * * @return Prawda, jeśli klient jest podłączony. Fałsz, inaczej. */ public boolean isOnline() { return connection.isConnected(); } /** * Zwraca instancję {@link Connection} klienta. */ public Connection getConnection() { return connection; } }

Połączenie.java

import java.io. DataInputStream; import java.io. DataOutputStream; import java.io. IOException; import java.net. Socket; import java.net. SocketException; /** * Klasa {@code Connection} reprezentuje połączenie od serwera do klienta lub punkt końcowy klienta w sieci * {@code Connection} po połączeniu może wymieniać dane z inną stroną lub stronami, w zależności od na serwerze * implementacja. *

* Ta klasa jest bezpieczna wątkowo. * * @wersja 1.0 * @see Serwer * @see Klient */ public class Połączenie implementuje Runnable { private Socket socket; prywatne wyjście DataOutputStream; prywatny DataInputStream w; prywatny wątek wątku; private final Object writeLock = new Object(); private final Object readLock = new Object(); /** * Konstruuje {@code Connection} przy użyciu strumieni określonego {@link Socket}. * * @param socket Gniazdo, z którego pobierane są strumienie.*/ public Connection(gniazdo) throws NetworkException { if (socket == null) { throw new IllegalArgumentException("gniazdo puste"); } this.socket = gniazdo; try { out = new DataOutputStream(socket.getOutputStream()); } catch (IOException e) { throw new NetworkException("Nie można uzyskać dostępu do strumienia wyjściowego.", e); } try { in = new DataInputStream(socket.getInputStream()); } catch (IOException e) { throw new NetworkException("Nie można uzyskać dostępu do strumienia wejściowego.", e); } wątek = nowy wątek(to); wątek.start(); } /** * Czyta wiadomości, gdy połączenie z drugą stroną jest aktywne. */ @Override public void run() { while (!socket.isClosed()) { spróbuj { int identyfikator; bajt bajty; synced (readLock) { identyfikator = in.readInt(); int length = in.readInt(); if (długość > 0) { bajty = nowy bajt[długość]; in.readFully(bajty, 0, bajty.długość); } inny { kontynuuj; } } switch (identyfikator) { case Identifier. INTERNAL: String command = new String(bytes); if (command.equals("rozłącz")) { if (!socket.isClosed()) { System.out.println("Odebrano pakiet rozłączający."); spróbuj { zamknij(); } catch (NetworkException e) { return; } } } przerwa; case Identifier. TEXT: System.out.println("Odebrana wiadomość: " + new String(bytes)); przerwa; domyślnie: System.out.println("Otrzymano nierozpoznane dane."); } } catch (SocketException e) { if (!e.getMessage().equals("Gniazdo zamknięte")) { e.printStackTrace(); } } catch (IOException e) { e.printStackTrace(); } } } /** * Wysyła dane do drugiej strony. * * @param data Dane do wysłania. * @throws NetworkException Jeśli zapis do strumienia wyjściowego nie powiedzie się. * @throws IllegalStateException W przypadku próby zapisu danych po zamknięciu połączenia. * @throws IllegalArgumentException Jeśli dane do wysłania mają wartość NULL. * @throws UnsupportedOperationException W przypadku próby wysłania nieobsługiwanego typu danych. */ public void send(Object data) throws NetworkException { if (socket.isClosed()) { throw new IllegalStateException("Dane nie zostały wysłane, połączenie jest zamknięte."); } if (data == null) { throw new IllegalArgumentException("dane null"); } int identyfikator; bajt bajty; if (instancja danych String) { identyfikator = Identyfikator. TEKST; bajty = ((ciąg) dane).getBytes(); } else { throw new UnsupportedOperationException("Nieobsługiwany typ danych: " + data.getClass()); } spróbuj { zsynchronizowane (writeLock) { out.writeInt(identyfikator); out.writeInt(bajty.długość); out.write(bajty); out.flush(); } } catch (IOException e) { throw new NetworkException("Nie można wysłać danych.", e); } } /** * Wysyła wiadomość o rozłączeniu i zamyka połączenie z drugą stroną. */ public void close() throws NetworkException { if (socket.isClosed()) { throw new IllegalStateException("Połączenie jest już zamknięte."); } try { byte message = "rozłącz".getBytes(); zsynchronizowane (writeLock) { out.writeInt(Identyfikator. INTERNAL); out.writeInt(wiadomość.długość); out.write(wiadomość); out.flush(); } } catch (IOException e) { System.out.println("Nie można wysłać komunikatu o rozłączeniu."); } spróbuj { zsynchronizowane (writeLock) { out.close(); } } catch (IOException e) { throw new NetworkException("Błąd podczas zamykania połączenia.", e); } wreszcie { thread.interrupt(); } } /** * Zwraca czy połączenie z drugą stroną jest aktywne. * * @return Prawda, jeśli połączenie jest aktywne. Fałsz, inaczej. */ public boolean isConnected() { return !socket.isClosed(); } }

Identyfikator.java

/** * Klasa {@code Identifier} zawiera stałe używane przez {@link Connection} do serializacji i deserializacji danych * przesyłanych przez sieć. * * @version 1.0 * @see Połączenie */ public final class Identyfikator { /** * Identyfikator wiadomości wewnętrznych. */ public static final int INTERNAL = 1; /** * Identyfikator wiadomości tekstowych. */ public static final int TEKST = 2; }

NetworkException.java

/** * Klasa {@code NetworkException} wskazuje na błąd związany z siecią. */ public class NetworkException extends Exception { /** * Konstruuje {@code NetworkException} z {@code null} jako komunikatem. */ public NetworkException() { } /** * Konstruuje {@code NetworkException} z określonym komunikatem. * * @param message Komunikat opisujący błąd. */ public NetworkException(String message) { super(message); } /** * Konstruuje {@code NetworkException} z określonym komunikatem i przyczyną. * * @param message Komunikat opisujący błąd. * @param Cause Przyczyna błędu. */ public NetworkException(String message, Throwable przyczyny) { super(message, Cause); } /** * Konstruuje {@code NetworkException} z określoną przyczyną. * * @param Cause Przyczyna błędu. */ public NetworkException(wyrzucana przyczyna) { super(przyczyna); } }

Przykład użycia.java

/** * Klasa {@code UsageExample} pokazuje użycie {@link Server} i {@link Client}. W tym przykładzie użyto * {@link Thread#sleep(long)}, aby zapewnić wykonanie każdego segmentu, ponieważ szybkie uruchamianie i zamykanie powoduje, że niektóre * segmenty nie są wykonywane. * * @wersja 1.0 * @see Serwer * @see Klient */ public class PrzykładUsytu { public static void main(String args) throws Exception { String host = "localhost"; port wewnętrzny = 10430; Serwer serwer = nowy Serwer(host, port); Klient klient = nowy Klient (host, port); Wątek.sen (100L); klient.send("Cześć."); server.broadcast("Hej kolego!"); Wątek.sen (100L); server.disconnect(server.getConnections()[0]); // lub client.close(), aby rozłączyć się z serwerem po stronie klienta.close(); } }

Zalecana: