Het schrijven van code die op een bepaald apparaat wordt uitgevoerd, geeft veel voldoening. Maar het schrijven van code die wordt uitgevoerd op verschillende apparaten die met elkaar communiceren, is gewoon levensbevestigend. Dit artikel leert u hoe u verbinding kunt maken en berichten kunt uitwisselen via een netwerk met behulp van het Transmission Control Protocol (TCP).
In dit artikel ga je een applicatie opzetten die je computer met zichzelf verbindt en, in wezen, het gek maakt - tegen zichzelf praat. Je leert ook het verschil tussen de twee meest gebruikte streams voor netwerken in Java en hoe ze werken.
Gegevens- en objectstromen
Voordat we in de code duiken, moet het verschil tussen de twee stromen die in het artikel worden gebruikt, worden onderscheiden.
Gegevensstromen
Datastromen verwerken primitieve datatypes en strings. Gegevens die via gegevensstromen worden verzonden, moeten handmatig worden geserialiseerd en gedeserialiseerd, wat het moeilijker maakt om complexe gegevens over te dragen. Maar datastromen kunnen communiceren met servers en clients die in andere talen dan Java zijn geschreven. Ruwe stromen zijn in dat opzicht vergelijkbaar met gegevensstromen, maar gegevensstromen zorgen ervoor dat de gegevens op een platformonafhankelijke manier worden geformatteerd, wat gunstig is omdat beide partijen verzonden gegevens kunnen lezen.
Objectstromen
Objectstromen verwerken primitieve gegevenstypen en objecten die worden geïmplementeerd
serialiseerbaar
koppel. Gegevens die via objectstromen worden verzonden, worden automatisch geserialiseerd en gedeserialiseerd, wat het gemakkelijker maakt om complexe gegevens over te dragen. Objectstromen kunnen echter alleen communiceren met servers en clients die in Java zijn geschreven. Ook,
ObjectUitvoerStream
bij initialisatie, stuurt een header naar de
InvoerStream
van de andere partij die, bij initialisatie, de uitvoering blokkeert totdat de header is ontvangen.
Stappen
Stap 1. Maak een klas aan
Maak een klas aan en noem deze zoals je wilt. In dit artikel wordt het genoemd
NetwerkAppVoorbeeld
openbare klasse NetworkAppExample { }
Stap 2. Maak een hoofdmethode aan
Maak een hoofdmethode en declareer dat deze uitzonderingen van kan veroorzaken
Uitzondering
type en elke subklasse ervan - alle uitzonderingen. Dit wordt als een slechte gewoonte beschouwd, maar is acceptabel voor barebone-voorbeelden.
openbare klasse NetworkAppExample { public static void main (String args) gooit Exception {} }
Stap 3. Declareer het serveradres
In dit voorbeeld wordt een lokaal hostadres en een willekeurig poortnummer gebruikt. Het poortnummer moet tussen 0 en 65535 (inclusief) liggen. De te vermijden poortnummers variëren echter van 0 tot 1023 (inclusief) omdat het gereserveerde systeempoorten zijn.
public class NetworkAppExample { public static void main (String args) gooit Exception { String host = "localhost"; int-poort = 10430; } }
Stap 4. Maak een server aan
Server is gebonden aan het adres en de poort en luistert naar inkomende verbindingen. op Java,
ServerSocket
staat voor het eindpunt aan de serverzijde en de functie ervan is het accepteren van nieuwe verbindingen.
ServerSocket
heeft geen streams voor het lezen en verzenden van gegevens omdat het geen verbinding tussen een server en een client vertegenwoordigt.
import java.net. InetAddress; java.net. ServerSocket importeren; public class NetworkAppExample { public static void main (String args) gooit Exception { String host = "localhost"; int-poort = 10430; ServerSocket-server = nieuwe ServerSocket(poort, 50, InetAddress.getByName(host)); } }
Stap 5. Start van de logserver
Druk voor logboekdoeleinden af naar de console die server is gestart.
import java.net. InetAddress; java.net. ServerSocket importeren; public class NetworkAppExample { public static void main (String args) gooit Exception { String host = "localhost"; int-poort = 10430; ServerSocket-server = nieuwe ServerSocket(poort, 50, InetAddress.getByName(host)); System.out.println("Server gestart."); } }
Stap 6. Maak een klant aan
Client is gebonden aan het adres en de poort van een server en luistert naar pakketten (berichten) nadat de verbinding tot stand is gebracht. op Java,
Stopcontact
vertegenwoordigt ofwel een eindpunt aan de clientzijde dat is verbonden met de server of een verbinding (van de server) naar de client en wordt gebruikt om te communiceren met de partij aan de andere kant.
import java.net. InetAddress; java.net. ServerSocket importeren; import java.net. Socket; public class NetworkAppExample { public static void main (String args) gooit Exception { String host = "localhost"; int-poort = 10430; ServerSocket-server = nieuwe ServerSocket(poort, 50, InetAddress.getByName(host)); System.out.println("Server gestart."); Socket-client = nieuwe Socket (host, poort); } }
Stap 7. Log verbindingspoging
Druk voor logboekdoeleinden af naar de console die verbinding is geprobeerd.
import java.net. InetAddress; java.net. ServerSocket importeren; import java.net. Socket; public class NetworkAppExample { public static void main (String args) gooit Exception { String host = "localhost"; int-poort = 10430; ServerSocket-server = nieuwe ServerSocket(poort, 50, InetAddress.getByName(host)); System.out.println("Server gestart."); Socket-client = nieuwe Socket (host, poort); System.out.println("Verbinding maken met server…"); } }
Stap 8. Maak verbinding
Clients zullen nooit verbinding maken tenzij de server luistert naar en accepteert, met andere woorden, verbindingen tot stand brengt. In Java worden verbindingen tot stand gebracht met
aanvaarden()
methode van
ServerSocket
klas. De methode blokkeert de uitvoering totdat een client verbinding maakt.
import java.net. InetAddress; java.net. ServerSocket importeren; import java.net. Socket; public class NetworkAppExample { public static void main (String args) gooit Exception { String host = "localhost"; int-poort = 10430; ServerSocket-server = nieuwe ServerSocket(poort, 50, InetAddress.getByName(host)); System.out.println("Server gestart."); Socket-client = nieuwe Socket (host, poort); System.out.println("Verbinding maken met server…"); Socketverbinding = server.accept(); } }
Stap 9. Log de tot stand gebrachte verbinding in
Voor logboekdoeleinden drukt u naar de console af dat de verbinding tussen server en client tot stand is gebracht.
import java.net. InetAddress; java.net. ServerSocket importeren; import java.net. Socket; public class NetworkAppExample { public static void main (String args) gooit Exception { String host = "localhost"; int-poort = 10430; ServerSocket-server = nieuwe ServerSocket(poort, 50, InetAddress.getByName(host)); System.out.println("Server gestart."); Socket-client = nieuwe Socket (host, poort); System.out.println("Verbinding maken met server…"); Socketverbinding = server.accept(); System.out.println("Verbinding tot stand gebracht."); } }
Stap 10. Bereid communicatiestromen voor
Communicatie vindt plaats via streams en in deze toepassing moeten onbewerkte streams van (verbinding van) server (naar client) en client worden geketend aan data- of objectstreams. Onthoud dat beide partijen hetzelfde streamtype moeten gebruiken.
-
Gegevensstromen
import java.io. DataInputStream; import java.io. DataOutputStream; import java.net. InetAddress; java.net. ServerSocket importeren; import java.net. Socket; public class NetworkAppExample { public static void main (String args) gooit Exception { String host = "localhost"; int-poort = 10430; ServerSocket-server = nieuwe ServerSocket(poort, 50, InetAddress.getByName(host)); System.out.println("Server gestart."); Socket-client = nieuwe Socket (host, poort); System.out.println("Verbinding maken met server…"); Socketverbinding = server.accept(); System.out.println("Verbinding tot stand gebracht."); DataOutputStream clientOut = nieuwe DataOutputStream(client.getOutputStream()); DataInputStream clientIn = nieuwe DataInputStream(client.getInputStream()); DataOutputStream serverOut = nieuwe DataOutputStream(connection.getOutputStream()); DataInputStream serverIn = nieuwe DataInputStream(verbinding.getInputStream()); } }
-
Objectstromen
Wanneer meerdere objectstromen worden gebruikt, moeten invoerstromen in dezelfde volgorde worden geïnitialiseerd als uitvoerstromen omdat:
ObjectOutputStream
stuurt een header naar de andere partij en
ObjectInputStream
blokkeert de uitvoering totdat de header wordt gelezen.
import java.io. ObjectInputStream; java.io. ObjectOutputStream importeren; import java.net. InetAddress; java.net. ServerSocket importeren; import java.net. Socket; public class NetworkAppExample { public static void main (String args) gooit Exception { String host = "localhost"; int-poort = 10430; ServerSocket-server = nieuwe ServerSocket(poort, 50, InetAddress.getByName(host)); System.out.println("Server gestart."); Socket-client = nieuwe Socket (host, poort); System.out.println("Verbinding maken met server…"); Socketverbinding = server.accept(); System.out.println("Verbinding tot stand gebracht."); ObjectOutputStream clientOut = nieuwe ObjectOutputStream(client.getOutputStream()); ObjectOutputStream serverOut = nieuwe ObjectOutputStream(connection.getOutputStream()); ObjectInputStream clientIn = nieuwe ObjectInputStream(client.getInputStream()); ObjectInputStream serverIn = nieuwe ObjectInputStream(verbinding.getInputStream()); } }
Volgorde zoals gespecificeerd in de bovenstaande code is misschien gemakkelijker te onthouden - initialiseer eerst de uitvoerstromen en vervolgens de invoerstromen in dezelfde volgorde. Een andere volgorde voor het initialiseren van objectstromen is echter de volgende:
ObjectOutputStream clientOut = nieuwe ObjectOutputStream(client.getOutputStream()); ObjectInputStream serverIn = nieuwe ObjectInputStream(verbinding.getInputStream()); ObjectOutputStream serverOut = nieuwe ObjectOutputStream(connection.getOutputStream()); ObjectInputStream clientIn = nieuwe ObjectInputStream(client.getInputStream());
Stap 11. Log in dat de communicatie gereed is
Druk voor logboekdoeleinden af naar de console dat de communicatie gereed is.
// code weggelaten import java.net. InetAddress; java.net. ServerSocket importeren; import java.net. Socket; public class NetworkAppExample { public static void main (String args) gooit Exception { String host = "localhost"; int-poort = 10430; ServerSocket-server = nieuwe ServerSocket(poort, 50, InetAddress.getByName(host)); System.out.println("Server gestart."); Socket-client = nieuwe Socket (host, poort); System.out.println("Verbinding maken met server…"); Socketverbinding = server.accept(); System.out.println("Verbinding tot stand gebracht."); // code weggelaten System.out.println ("Communicatie is gereed."); } }
Stap 12. Maak een bericht aan
In deze toepassing,
Hallo Wereld
tekst wordt naar de server verzonden als
byte
of
Snaar
. Declareer een variabele van het type dat afhangt van de gebruikte stream. Gebruik maken van
byte
voor datastromen en
Snaar
voor objectstromen.
-
Gegevensstromen
Met behulp van datastromen wordt serialisatie gedaan door objecten om te zetten in primitieve datatypes of a
Snaar
. In dit geval,
Snaar
wordt geconverteerd naar
byte
in plaats van geschreven met behulp van
schrijfBytes()
methode om te laten zien hoe het zou zijn met andere objecten, zoals afbeeldingen of andere bestanden.
import java.io. DataInputStream; import java.io. DataOutputStream; import java.net. InetAddress; java.net. ServerSocket importeren; import java.net. Socket; public class NetworkAppExample { public static void main (String args) gooit Exception { String host = "localhost"; int-poort = 10430; ServerSocket-server = nieuwe ServerSocket(poort, 50, InetAddress.getByName(host)); System.out.println("Server gestart."); Socket-client = nieuwe Socket (host, poort); System.out.println("Verbinding maken met server…"); Socketverbinding = server.accept(); System.out.println("Verbinding tot stand gebracht."); DataOutputStream clientOut = nieuwe DataOutputStream(client.getOutputStream()); DataInputStream clientIn = nieuwe DataInputStream(client.getInputStream()); DataOutputStream serverOut = nieuwe DataOutputStream(connection.getOutputStream()); DataInputStream serverIn = nieuwe DataInputStream(verbinding.getInputStream()); System.out.println("Communicatie is gereed."); byte messageOut = "Hallo wereld".getBytes(); } }
-
Objectstromen
import java.io. ObjectInputStream; java.io. ObjectOutputStream importeren; import java.net. InetAddress; java.net. ServerSocket importeren; import java.net. Socket; public class NetworkAppExample { public static void main (String args) gooit Exception { String host = "localhost"; int-poort = 10430; ServerSocket-server = nieuwe ServerSocket(poort, 50, InetAddress.getByName(host)); System.out.println("Server gestart."); Socket-client = nieuwe Socket (host, poort); System.out.println("Verbinding maken met server…"); Socketverbinding = server.accept(); System.out.println("Verbinding tot stand gebracht."); ObjectOutputStream clientOut = nieuwe ObjectOutputStream(client.getOutputStream()); ObjectOutputStream serverOut = nieuwe ObjectOutputStream(connection.getOutputStream()); ObjectInputStream clientIn = nieuwe ObjectInputStream(client.getInputStream()); ObjectInputStream serverIn = nieuwe ObjectInputStream(verbinding.getInputStream()); System.out.println("Communicatie is gereed."); String messageOut = "Hallo wereld"; } }
Stap 13. Verstuur het bericht
Schrijf gegevens naar de uitvoerstroom en spoel de stroom om ervoor te zorgen dat de gegevens volledig zijn geschreven.
-
Gegevensstromen
De lengte van een bericht moet eerst worden verzonden, zodat de andere partij weet hoeveel bytes het moet lezen. Nadat de lengte is verzonden als een primitief geheel getal, kunnen bytes worden verzonden.
import java.io. DataInputStream; import java.io. DataOutputStream; import java.net. InetAddress; java.net. ServerSocket importeren; import java.net. Socket; public class NetworkAppExample { public static void main (String args) gooit Exception { String host = "localhost"; int-poort = 10430; ServerSocket-server = nieuwe ServerSocket(poort, 50, InetAddress.getByName(host)); System.out.println("Server gestart."); Socket-client = nieuwe Socket (host, poort); System.out.println("Verbinding maken met server…"); Socketverbinding = server.accept(); System.out.println("Verbinding tot stand gebracht."); DataOutputStream clientOut = nieuwe DataOutputStream(client.getOutputStream()); DataInputStream clientIn = nieuwe DataInputStream(client.getInputStream()); DataOutputStream serverOut = nieuwe DataOutputStream(connection.getOutputStream()); DataInputStream serverIn = nieuwe DataInputStream(verbinding.getInputStream()); System.out.println("Communicatie is gereed."); byte messageOut = "Hallo wereld".getBytes(); clientOut.writeInt(messageOut.length); clientOut.write (berichtUit); clientOut.flush(); } }
-
Objectstromen
import java.io. ObjectInputStream; import java.io. ObjectOutputStream; import java.net. InetAddress; java.net. ServerSocket importeren; import java.net. Socket; public class NetworkAppExample { public static void main (String args) gooit Exception { String host = "localhost"; int-poort = 10430; ServerSocket-server = nieuwe ServerSocket(poort, 50, InetAddress.getByName(host)); System.out.println("Server gestart."); Socket-client = nieuwe Socket (host, poort); System.out.println("Verbinding maken met server…"); Socketverbinding = server.accept(); System.out.println("Verbinding tot stand gebracht."); ObjectOutputStream clientOut = nieuwe ObjectOutputStream(client.getOutputStream()); ObjectOutputStream serverOut = nieuwe ObjectOutputStream(connection.getOutputStream()); ObjectInputStream clientIn = nieuwe ObjectInputStream(client.getInputStream()); ObjectInputStream serverIn = nieuwe ObjectInputStream(verbinding.getInputStream()); System.out.println("Communicatie is gereed."); String messageOut = "Hallo wereld"; clientOut.writeObject(berichtUit); clientOut.flush(); } }
Stap 14. Log verzonden bericht
Druk voor logboekdoeleinden af naar de console dat het bericht is verzonden.
-
Gegevensstromen
import java.io. DataInputStream; import java.io. DataOutputStream; import java.net. InetAddress; java.net. ServerSocket importeren; import java.net. Socket; public class NetworkAppExample { public static void main (String args) gooit Exception { String host = "localhost"; int-poort = 10430; ServerSocket-server = nieuwe ServerSocket(poort, 50, InetAddress.getByName(host)); System.out.println("Server gestart."); Socket-client = nieuwe Socket (host, poort); System.out.println("Verbinding maken met server…"); Socketverbinding = server.accept(); System.out.println("Verbinding tot stand gebracht."); DataOutputStream clientOut = nieuwe DataOutputStream(client.getOutputStream()); DataInputStream clientIn = nieuwe DataInputStream(client.getInputStream()); DataOutputStream serverOut = nieuwe DataOutputStream(connection.getOutputStream()); DataInputStream serverIn = nieuwe DataInputStream(verbinding.getInputStream()); System.out.println("Communicatie is gereed."); byte messageOut = "Hallo wereld".getBytes(); clientOut.writeInt(messageOut.length); clientOut.write (berichtUit); clientOut.flush(); System.out.println("Bericht verzonden naar server: " + new String(messageOut)); } }
-
Objectstromen
import java.io. ObjectInputStream; import java.io. ObjectOutputStream; import java.net. InetAddress; java.net. ServerSocket importeren; import java.net. Socket; public class NetworkAppExample { public static void main (String args) gooit Exception { String host = "localhost"; int-poort = 10430; ServerSocket-server = nieuwe ServerSocket(poort, 50, InetAddress.getByName(host)); System.out.println("Server gestart."); Socket-client = nieuwe Socket (host, poort); System.out.println("Verbinding maken met server…"); Socketverbinding = server.accept(); System.out.println("Verbinding tot stand gebracht."); ObjectOutputStream clientOut = nieuwe ObjectOutputStream(client.getOutputStream()); ObjectOutputStream serverOut = nieuwe ObjectOutputStream(connection.getOutputStream()); ObjectInputStream clientIn = nieuwe ObjectInputStream(client.getInputStream()); ObjectInputStream serverIn = nieuwe ObjectInputStream(verbinding.getInputStream()); System.out.println("Communicatie is gereed."); String messageOut = "Hallo wereld"; clientOut.writeObject(berichtUit); clientOut.flush(); System.out.println("Bericht verzonden naar server: " + messageOut); } }
Stap 15. Lees het bericht
Gegevens uit de invoerstroom lezen en converteren. Aangezien we precies het type verzonden gegevens weten, zullen we ofwel een
Snaar
van
byte
of cast
Object
tot
Snaar
zonder te controleren, afhankelijk van de gebruikte stream.
-
Gegevensstromen
Omdat de lengte eerst werd verzonden en daarna de bytes, moet het lezen in dezelfde volgorde worden gedaan. Als de lengte nul is, is er niets te lezen. Object wordt gedeserialiseerd wanneer bytes weer worden geconverteerd naar een instantie, in dit geval van
Snaar
import java.io. DataInputStream; import java.io. DataOutputStream; import java.net. InetAddress; java.net. ServerSocket importeren; import java.net. Socket; public class NetworkAppExample { public static void main (String args) gooit Exception { String host = "localhost"; int-poort = 10430; ServerSocket-server = nieuwe ServerSocket(poort, 50, InetAddress.getByName(host)); System.out.println("Server gestart."); Socket-client = nieuwe Socket (host, poort); System.out.println("Verbinding maken met server…"); Socketverbinding = server.accept(); System.out.println("Verbinding tot stand gebracht."); DataOutputStream clientOut = nieuwe DataOutputStream(client.getOutputStream()); DataInputStream clientIn = nieuwe DataInputStream(client.getInputStream()); DataOutputStream serverOut = nieuwe DataOutputStream(connection.getOutputStream()); DataInputStream serverIn = nieuwe DataInputStream(verbinding.getInputStream()); System.out.println("Communicatie is gereed."); byte messageOut = "Hallo wereld".getBytes(); clientOut.writeInt(messageOut.length); clientOut.write (berichtUit); clientOut.flush(); System.out.println("Bericht verzonden naar server: " + new String(messageOut)); int lengte = serverIn.readInt(); if (lengte > 0) { byte messageIn = nieuwe byte[lengte]; serverIn.readFully(messageIn, 0, messageIn.length); } } }
-
Objectstromen
import java.io. ObjectInputStream; import java.io. ObjectOutputStream; import java.net. InetAddress; java.net. ServerSocket importeren; import java.net. Socket; public class NetworkAppExample { public static void main (String args) gooit Exception { String host = "localhost"; int-poort = 10430; ServerSocket-server = nieuwe ServerSocket(poort, 50, InetAddress.getByName(host)); System.out.println("Server gestart."); Socket-client = nieuwe Socket (host, poort); System.out.println("Verbinding maken met server…"); Socketverbinding = server.accept(); System.out.println("Verbinding tot stand gebracht."); ObjectOutputStream clientOut = nieuwe ObjectOutputStream(client.getOutputStream()); ObjectOutputStream serverOut = nieuwe ObjectOutputStream(connection.getOutputStream()); ObjectInputStream clientIn = nieuwe ObjectInputStream(client.getInputStream()); ObjectInputStream serverIn = nieuwe ObjectInputStream(verbinding.getInputStream()); System.out.println("Communicatie is gereed."); String messageOut = "Hallo wereld"; clientOut.writeObject(berichtUit); clientOut.flush(); System.out.println("Bericht verzonden naar server: " + messageOut); String messageIn = (String) serverIn.readObject(); } }
Stap 16. Log gelezen bericht
Druk voor logboekdoeleinden af naar de console dat het bericht is ontvangen en druk de inhoud ervan af.
-
Gegevensstromen
import java.io. DataInputStream; import java.io. DataOutputStream; import java.net. InetAddress; java.net. ServerSocket importeren; import java.net. Socket; public class NetworkAppExample { public static void main (String args) gooit Exception { String host = "localhost"; int-poort = 10430; ServerSocket-server = nieuwe ServerSocket(poort, 50, InetAddress.getByName(host)); System.out.println("Server gestart."); Socket-client = nieuwe Socket (host, poort); System.out.println("Verbinding maken met server…"); Socketverbinding = server.accept(); System.out.println("Verbinding tot stand gebracht."); DataOutputStream clientOut = nieuwe DataOutputStream(client.getOutputStream()); DataInputStream clientIn = nieuwe DataInputStream(client.getInputStream()); DataOutputStream serverOut = nieuwe DataOutputStream(connection.getOutputStream()); DataInputStream serverIn = nieuwe DataInputStream(verbinding.getInputStream()); System.out.println("Communicatie is gereed."); byte messageOut = "Hallo wereld".getBytes(); clientOut.writeInt(messageOut.length); clientOut.write (berichtUit); clientOut.flush(); System.out.println("Bericht verzonden naar server: " + new String(messageOut)); int lengte = serverIn.readInt(); if (lengte > 0) { byte messageIn = nieuwe byte[lengte]; serverIn.readFully(messageIn, 0, messageIn.length); System.out.println("Bericht ontvangen van klant: " + new String(messageIn)); } } }
-
Objectstromen
import java.io. ObjectInputStream; import java.io. ObjectOutputStream; import java.net. InetAddress; java.net. ServerSocket importeren; import java.net. Socket; public class NetworkAppExample { public static void main (String args) gooit Exception { String host = "localhost"; int-poort = 10430; ServerSocket-server = nieuwe ServerSocket(poort, 50, InetAddress.getByName(host)); System.out.println("Server gestart."); Socket-client = nieuwe Socket (host, poort); System.out.println("Verbinding maken met server…"); Socketverbinding = server.accept(); System.out.println("Verbinding tot stand gebracht."); ObjectOutputStream clientOut = nieuwe ObjectOutputStream(client.getOutputStream()); ObjectOutputStream serverOut = nieuwe ObjectOutputStream(connection.getOutputStream()); ObjectInputStream clientIn = nieuwe ObjectInputStream(client.getInputStream()); ObjectInputStream serverIn = nieuwe ObjectInputStream(verbinding.getInputStream()); System.out.println("Communicatie is gereed."); String messageOut = "Hallo wereld"; clientOut.writeObject(berichtUit); clientOut.flush(); System.out.println("Bericht verzonden naar server: " + messageOut); String messageIn = (String) serverIn.readObject(); System.out.println("Bericht ontvangen van cliënt: " + messageIn); } }
Stap 17. Koppel verbindingen los
De verbinding wordt verbroken wanneer een partij zijn streams afsluit. In Java worden door de uitvoerstroom te sluiten, ook de bijbehorende socket en invoerstroom gesloten. Zodra een partij aan de andere kant ontdekt dat de verbinding is verbroken, moet deze ook de uitvoerstroom sluiten om geheugenlekken te voorkomen.
// code weggelaten import java.net. InetAddress; java.net. ServerSocket importeren; import java.net. Socket; public class NetworkAppExample { public static void main (String args) gooit Exception { String host = "localhost"; int-poort = 10430; ServerSocket-server = nieuwe ServerSocket(poort, 50, InetAddress.getByName(host)); System.out.println("Server gestart."); Socket-client = nieuwe Socket (host, poort); System.out.println("Verbinding maken met server…"); Socketverbinding = server.accept(); System.out.println("Verbinding tot stand gebracht."); // code weggelaten System.out.println ("Communicatie is gereed."); // code weggelaten clientOut.close(); serverOut.close(); } }
Stap 18. Log loskoppeling
Voor logboekdoeleinden zijn de verbindingen naar de console verbroken.
// code weggelaten import java.net. InetAddress; java.net. ServerSocket importeren; import java.net. Socket; public class NetworkAppExample { public static void main (String args) gooit Exception { String host = "localhost"; int-poort = 10430; ServerSocket-server = nieuwe ServerSocket(poort, 50, InetAddress.getByName(host)); System.out.println("Server gestart."); Socket-client = nieuwe Socket (host, poort); System.out.println("Verbinding maken met server…"); Socketverbinding = server.accept(); System.out.println("Verbinding tot stand gebracht."); // code weggelaten System.out.println ("Communicatie is gereed."); // code weggelaten clientOut.close(); serverOut.close(); System.out.println("Verbindingen gesloten."); } }
Stap 19. Beëindig de server
Verbindingen zijn verbroken, maar de server is nog steeds actief. Als
ServerSocket
is niet gekoppeld aan een stream, het moet expliciet worden gesloten door te bellen
dichtbij()
methode.
// code weggelaten import java.net. InetAddress; java.net. ServerSocket importeren; import java.net. Socket; public class NetworkAppExample { public static void main (String args) gooit Exception { String host = "localhost"; int-poort = 10430; ServerSocket-server = nieuwe ServerSocket(poort, 50, InetAddress.getByName(host)); System.out.println("Server gestart."); Socket-client = nieuwe Socket (host, poort); System.out.println("Verbinding maken met server…"); Socketverbinding = server.accept(); System.out.println("Verbinding tot stand gebracht."); // code weggelaten System.out.println ("Communicatie is gereed."); // code weggelaten clientOut.close(); serverOut.close(); System.out.println("Verbindingen gesloten."); server.sluiten(); } }
Stap 20. Beëindiging van de logserver
Voor logboekdoeleinden is het afdrukken naar de consoleserver beëindigd.
// code weggelaten import java.net. InetAddress; java.net. ServerSocket importeren; import java.net. Socket; public class NetworkAppExample { public static void main (String args) gooit Exception { String host = "localhost"; int-poort = 10430; ServerSocket-server = nieuwe ServerSocket(poort, 50, InetAddress.getByName(host)); System.out.println("Server gestart."); Socket-client = nieuwe Socket (host, poort); System.out.println("Verbinding maken met server…"); Socketverbinding = server.accept(); System.out.println("Verbinding tot stand gebracht."); // code weggelaten System.out.println ("Communicatie is gereed."); // code weggelaten clientOut.close(); serverOut.close(); System.out.println("Verbindingen gesloten."); server.sluiten(); System.out.println("Server beëindigd."); } }
Stap 21. Compileren en uitvoeren
Door te loggen konden we weten of de aanvraag succesvol was of niet. Verwachte resultaten:
Server gestart. Verbinding maken met server… Verbinding tot stand gebracht. Communicatie is klaar. Bericht verzonden naar server: Hello World Bericht ontvangen van client: Hello World Connections gesloten. Server beëindigd.
Als uw uitvoer niet is zoals hierboven, wat waarschijnlijk niet zal gebeuren, zijn er een paar oplossingen:
-
Als de uitvoer stopt bij de lijn
Verbinding gemaakt.
en objectstromen worden gebruikt, spoel ze elk door
ObjectOutputStream
- onmiddellijk na initialisatie omdat headers om de een of andere reden niet werden verzonden.
-
Als de uitvoer wordt afgedrukt
java.net. BindException: Adres al in gebruik
- kies een ander poortnummer omdat het opgegeven poortnummer al in gebruik is.
Tips
- Verbinding maken met een server op een ander netwerk wordt gedaan door verbinding te maken met het externe IP-adres van een apparaat waarop de server wordt uitgevoerd met een doorgestuurde poort.
- Verbinding maken met een server op hetzelfde netwerk wordt gedaan door ofwel verbinding te maken met het privé IP-adres van een apparaat waarop de server draait, of door een poort door te sturen en verbinding te maken met het externe IP-adres van het apparaat.
- Er is software, zoals Hamachi, waarmee verbinding kan worden gemaakt met de server op een ander netwerk zonder een poort door te sturen, maar hiervoor moet de software op beide apparaten worden geïnstalleerd.
Voorbeelden
Netwerktoepassingen die invoer/uitvoer blokkeren, moeten threads gebruiken. De volgende voorbeelden tonen een minimalistische server- en clientimplementatie met threads. De netwerkcode is in wezen hetzelfde als in het artikel, behalve dat sommige fragmenten zijn gesynchroniseerd, naar threads zijn verplaatst en uitzonderingen worden afgehandeld.
Server.java
import java.io. IOException; import java.net. InetAddress; java.net. ServerSocket importeren; import java.net. SocketException; import java.net. UnknownHostException; java.util. ArrayList importeren; java.util. Collecties importeren; import java.util. Lijst; /** * De klasse {@code Server} vertegenwoordigt een servereindpunt in een netwerk. {@code Server} eenmaal gebonden aan een bepaald IP*-adres en poort, maakt verbindingen met clients en kan met hen communiceren of de verbinding verbreken. *
* Deze klasse is threadsafe. * * @versie 1.0 * @see Client * @see Connection */ public class Server implementeert Runnable { private ServerSocket-server; privé lijst
verbindingen; privé Thread-thread; privé definitief Object verbindingenLock = new Object(); /** * Creëert een {@code Server} die communiceert met clients op de opgegeven hostnaam en poort met de opgegeven * gevraagde maximale lengte van een wachtrij van inkomende clients. * * @param host Hostadres dat moet worden gebruikt. * @param port Poortnummer dat moet worden gebruikt. * @param backlog Gevraagde maximale lengte van de wachtrij van inkomende clients. * @throws NetworkException Als er een fout optreedt tijdens het starten van een server. */ public Server (String host, int port, int backlog) gooit NetworkException {try {server = new ServerSocket(port, backlog, InetAddress.getByName(host)); } catch (UnknownHostException e) { throw new NetworkException("Hostnaam kon niet worden opgelost: " + host, e); } catch (IllegalArgumentException e) { throw new NetworkException("Poortnummer moet tussen 0 en 65535 liggen (inclusief): " + poort); } catch (IOException e) { throw new NetworkException ("Server kan niet worden gestart.", e); } verbindingen = Collections.synchronizedList(nieuwe ArrayList()); thread = nieuwe thread (dit); draad.start(); } /** * Creëert een {@code Server} die communiceert met clients op de opgegeven hostnaam en poort. * * @param host Hostadres om te binden. * @param port Poortnummer om te binden. * @throws NetworkException Als er fouten optreden bij het starten van een server. */ public Server (String host, int port) gooit NetworkException { this(host, port, 50); } /** * Luistert naar, accepteert en registreert inkomende verbindingen van clients. */ @Override public void run() { while (!server.isClosed()) { probeer {connections.add(new Connection(server.accept())); } catch (SocketException e) { if (!e.getMessage().equals("Socket gesloten")) { e.printStackTrace(); } } catch (NetworkException | IOException e) { e.printStackTrace(); } } } /** * Verzendt gegevens naar alle geregistreerde klanten. * * @param data Gegevens om te verzenden. * @throws IllegalStateException Als er wordt geprobeerd gegevens te schrijven terwijl de server offline is. * @throws IllegalArgumentException Als de te verzenden gegevens null zijn. */ public void broadcast (Object data) { if (server.isClosed()) { throw new IllegalStateException ("Gegevens niet verzonden, server is offline."); } if (data == null) { gooi nieuwe IllegalArgumentException ("null data"); } gesynchroniseerd (connectionsLock) { for (Verbindingsverbinding: verbindingen) { probeer {connection.send(data); System.out.println("Gegevens zijn succesvol naar de klant verzonden."); } catch (NetworkException e) { e.printStackTrace(); } } } } /** * Verzendt een bericht voor het verbreken van de verbinding en verbreekt de verbinding met de opgegeven client. * * @param verbinding Client om te verbreken. * @throws NetworkException Als er een fout optreedt bij het sluiten van de verbinding. */ public void disconnect (verbindingsverbinding) genereert NetworkException { if (connections.remove(connection)) { connection.close(); } } /** * Verzendt een bericht voor het verbreken van de verbinding naar alle clients, verbreekt de verbinding en beëindigt de server. */ public void close() gooit NetworkException {gesynchroniseerd (connectionsLock) { for (Verbindingsverbinding: verbindingen) {probeer {connection.close(); } catch (NetworkException e) { e.printStackTrace(); } } } verbindingen.clear(); probeer {server.close(); } catch (IOException e) { throw new NetworkException ("Fout bij het sluiten van de server."); } eindelijk { thread.interrupt(); } } /** * Geeft als resultaat of de server al dan niet online is. * * @return Waar als de server online is. Vals, anders. */ public boolean isOnline() { return !server.isClosed(); } /** * Retourneert een array van geregistreerde clients. */ public Connection getConnections() {synchronized (connectionsLock) {return verbindingen.toArray(nieuwe verbinding[connections.size()]); } } }
Client.java
import java.io. IOException; import java.net. Socket; import java.net. UnknownHostException; /** * De klasse {@code Client} vertegenwoordigt een client-eindpunt in een netwerk. {@code Client}, eenmaal verbonden met een bepaalde * server, kan gegarandeerd alleen communiceren met de server. Of andere clients de gegevens * ontvangen, hangt af van de serverimplementatie. *
* Deze klasse is threadsafe. * * @versie 1.0 * @see Server * @see Connection */ public class Client { private Connection connection; /** * Creëert een {@code Client} die is verbonden met de server op de opgegeven host en poort. * * @param host Hostadres om te binden. * @param port Poortnummer om te binden. * @throws NetworkException Als er een fout optreedt tijdens het starten van een server. */ public Client (String host, int port) gooit NetworkException {try { connection = new Connection (new Socket(host, port)); } catch (UnknownHostException e) { throw new NetworkException("Hostnaam kon niet worden opgelost: " + host, e); } catch (IllegalArgumentException e) { throw new NetworkException("Poortnummer moet tussen 0 en 65535 (inclusief): " + poort); } catch (IOException e) { throw new NetworkException ("Server kan niet worden gestart.", e); } } /** * Verzendt gegevens naar de andere partij. * * @param data Gegevens om te verzenden. * @throws NetworkException Als het schrijven naar de uitvoerstroom mislukt. * @throws IllegalStateException Als er wordt geprobeerd gegevens te schrijven terwijl de verbinding is verbroken. * @throws IllegalArgumentException Als de te verzenden gegevens null zijn. * @throws UnsupportedOperationException Als wordt geprobeerd een niet-ondersteund gegevenstype te verzenden. */ public void send (Object data) genereert NetworkException { connection.send(data); } /** * Verzendt een verbreekbericht naar en verbreekt de verbinding met de server. */ public void close() gooit NetworkException { connection.close(); } /** * Geeft terug of de client al dan niet is verbonden met de server. * * @return Waar als de client is verbonden. Vals, anders. */ public boolean isOnline() { return connection.isConnected(); } /** * Retourneert de {@link Connection}-instantie van de client. */ public Connection getConnection() { retourverbinding; } }
Verbinding.java
import java.io. DataInputStream; import java.io. DataOutputStream; import java.io. IOException; import java.net. Socket; import java.net. SocketException; /** * De klasse {@code Connection} vertegenwoordigt ofwel een verbinding van server naar client of een client-eindpunt in een netwerk * {@code Connection} kan, eenmaal verbonden, gegevens uitwisselen met andere partij of partijen, afhankelijk van op een server * implementatie. *
* Deze klasse is threadsafe. * * @versie 1.0 * @see Server * @see Client */ public class Verbinding implementeert Runnable { private Socket socket; privé DataOutputStream uit; privé DataInputStream in; privé Thread-thread; privé definitief Object writeLock = new Object(); privé definitief Object readLock = nieuw object (); /** * Construeert {@code Connection} met behulp van streams van een gespecificeerde {@link Socket}. * * @param socket Socket om de streams op te halen.*/ public Connection (socket socket) gooit NetworkException {if (socket == null) { throw new IllegalArgumentException ("null socket"); } dit.socket = socket; probeer {out = nieuwe DataOutputStream(socket.getOutputStream()); } catch (IOException e) { throw new NetworkException ("Kon geen toegang krijgen tot uitvoerstroom.", e); } probeer { in = nieuwe DataInputStream(socket.getInputStream()); } catch (IOException e) { throw new NetworkException ("Kon geen toegang krijgen tot invoerstroom.", e); } draad = nieuwe draad (dit); draad.start(); } /** * Leest berichten terwijl de verbinding met de andere partij actief is. */ @Override public void run() { while (!socket.isClosed()) { try { int identifier; byte bytes; gesynchroniseerd (readLock) { identifier = in.readInt(); int lengte = in.readInt(); if (lengte > 0) { bytes = nieuwe byte [lengte]; in.readFully(bytes, 0, bytes.length); } anders { ga verder; } } switch (identifier) { case Identifier. INTERNAL: String command = new String (bytes); if (command.equals("disconnect")) { if (!socket.isClosed()) { System.out.println("Verbindingspakket ontvangen."); probeer { sluiten(); } catch (NetworkException e) { return; } } } pauze; case Identifier. TEXT: System.out.println ("Bericht ontvangen: " + nieuwe String (bytes)); pauze; standaard: System.out.println("Onbekende gegevens ontvangen."); } } catch (SocketException e) { if (!e.getMessage().equals("Socket gesloten")) { e.printStackTrace(); } } catch (IOException e) { e.printStackTrace(); } } } /** * Verzendt gegevens naar de andere partij. * * @param data Gegevens om te verzenden. * @throws NetworkException Als het schrijven naar de uitvoerstroom mislukt. * @throws IllegalStateException Als er wordt geprobeerd gegevens te schrijven terwijl de verbinding is verbroken. * @throws IllegalArgumentException Als de te verzenden gegevens null zijn. * @throws UnsupportedOperationException Als wordt geprobeerd een niet-ondersteund gegevenstype te verzenden. */ public void send (Object data) gooit NetworkException { if (socket.isClosed()) { throw new IllegalStateException ("Gegevens niet verzonden, verbinding is gesloten."); } if (data == null) { gooi nieuwe IllegalArgumentException ("null data"); } int identifier; byte bytes; if (gegevensinstantie van String) { identifier = Identifier. TEXT; bytes = ((String) data).getBytes(); } else { throw new UnsupportedOperationException("Niet-ondersteund gegevenstype: " + data.getClass()); } probeer { gesynchroniseerd (writeLock) { out.writeInt(identifier); out.writeInt(bytes.lengte); uit.schrijven(bytes); uit.flush(); } } catch (IOException e) { throw new NetworkException ("Gegevens konden niet worden verzonden.", e); } } /** * Verzendt een verbreekbericht naar en verbreekt de verbinding met de andere partij. */ public void close() gooit NetworkException { if (socket.isClosed()) { throw new IllegalStateException ("Verbinding is al gesloten."); } probeer { byte message = "disconnect".getBytes(); gesynchroniseerd (writeLock) { out.writeInt(Identifier. INTERNAL); out.writeInt(bericht.lengte); out.write(bericht); uit.flush(); } } catch (IOException e) { System.out.println("Verbindingsbericht kon niet worden verzonden."); } probeer { gesynchroniseerd (writeLock) { out.close(); } } catch (IOException e) { throw new NetworkException ("Fout bij het sluiten van de verbinding.", e); } eindelijk { thread.interrupt(); } } /** * Geeft terug of de verbinding met de andere partij actief is. * * @return Waar als de verbinding actief is. Vals, anders. */ public boolean isConnected() { return! socket.isClosed(); } }
ID.java
/** * De klasse {@code Identifier} bevat constanten die worden gebruikt door {@link Connection} voor het serialiseren en deserialiseren van de gegevens * die via het netwerk worden verzonden. * * @versie 1.0 * @see Verbinding */ public final class Identifier { /** * Identifier voor interne berichten. */ openbare statische finale int INTERN = 1; /** * Identificatiecode voor tekstberichten. */ openbare statische finale int TEXT = 2; }
Netwerkuitzondering.java
/** * De klasse {@code NetworkException} geeft een netwerkfout aan. */ public class NetworkException breidt Exception uit { /** * Stelt een {@code NetworkException} samen met {@code null} als zijn bericht. */ public NetworkException() { } /** * Stelt een {@code NetworkException} samen met het opgegeven bericht. * * @param bericht Een bericht om de fout te beschrijven. */ public NetworkException (String-bericht) { super (bericht); } /** * Stelt een {@code NetworkException} samen met het opgegeven bericht en de oorzaak. * * @param bericht Een bericht om de fout te beschrijven. * @param oorzaak Een oorzaak van een fout. */ public NetworkException (String-bericht, weggooibare oorzaak) { super (bericht, oorzaak); } /** * Creëert een {@code NetworkException} met de opgegeven oorzaak. * * @param oorzaak Een oorzaak van een fout. */ public NetworkException (Gooibare oorzaak) { super (oorzaak); } }
UsageExample.java
/** * De klasse {@code UsageExample} toont het gebruik van {@link Server} en {@link Client}. Dit voorbeeld gebruikt * {@link Thread#sleep(long)} om ervoor te zorgen dat elk segment wordt uitgevoerd, omdat snel starten en sluiten ervoor zorgt dat sommige * segmenten niet worden uitgevoerd. * * @versie 1.0 * @see Server * @see Client */ public class UsageExample { public static void main (String args) throws Exception { String host = "localhost"; int-poort = 10430; Serverserver = nieuwe server(host, poort); Client client = nieuwe Client (host, poort); Draad.slaap (100L); client.send("Hallo."); server.broadcast("Hé, kerel!"); Draad.slaap (100L); server.disconnect(server.getConnections()[0]); // of client.close() om de verbinding met client-side server.close() te verbreken; } }