Att skriva kod som körs på en viss enhet är mycket tillfredsställande. Men att skriva kod som körs på flera enheter som kommunicerar med varandra är helt enkelt livsbekräftande. Den här artikeln kommer att lära dig hur du ansluter och utbyter meddelanden över nätverk med hjälp av överföringskontrollprotokoll (TCP).
I den här artikeln kommer du att konfigurera ett program som ansluter din dator till sig själv och i huvudsak gör det galet - prata med sig själv. Du kommer också att lära dig skillnaden mellan de två mest använda strömmarna för nätverk i Java och hur de fungerar.
Data- och objektströmmar
Innan du dyker ner i kod måste skillnaden mellan de två strömmar som används i artikeln särskiljas.
Dataströmmar
Dataströmmar behandlar primitiva datatyper och strängar. Data som skickas över dataströmmar måste seriellt och deserialiseras manuellt vilket gör det svårare att överföra komplexa data. Men dataströmmar kan kommunicera med servrar och klienter skrivna på andra språk än Java. Raw streams liknar dataströmmar i den aspekten, men dataströmmar säkerställer att data formateras på ett plattformsoberoende sätt vilket är fördelaktigt eftersom båda parter kommer att kunna läsa skickad data.
Objektströmmar
Objektströmmar bearbetar primitiva datatyper och objekt som implementerar
Serialiserbar
gränssnitt. Data som skickas över objektströmmar serialiseras och avserialiseras automatiskt vilket gör det lättare att överföra komplexa data. Men objektströmmar kan bara kommunicera med servrar och klienter skrivna i Java. Också,
ObjectOutputStream
vid initialisering skickar ett rubrik till
InputStream
från den andra parten som vid initialisering blockerar körning tills rubriken tas emot.
Steg
Steg 1. Skapa en klass
Skapa en klass och namnge den hur du vill. I den här artikeln kommer den att namnges
NetworkAppExample
public class NetworkAppExample {}
Steg 2. Skapa en huvudmetod
Skapa en huvudmetod och förklara att den kan ge undantag från
Undantag
typ och eventuell underklass - alla undantag. Detta anses vara en dålig praxis, men är acceptabelt för barebone -exempel.
public class NetworkAppExample {public static void main (String args) kastar undantag {}}
Steg 3. Deklarera serveradress
I det här exemplet används lokal värdadress och ett godtyckligt portnummer. Portnummer måste ligga i intervallet från 0 till 65535 (inklusive). Portnumren som ska undvikas varierar emellertid från 0 till 1023 (inklusive) eftersom de är reserverade systemportar.
public class NetworkAppExample {public static void main (String args) kastar undantag {String host = "localhost"; int port = 10430; }}
Steg 4. Skapa en server
Servern är bunden till adressen och porten och lyssnar efter inkommande anslutningar. I Java,
ServerSocket
representerar serversidan slutpunkt och dess funktion är att acceptera nya anslutningar.
ServerSocket
har inte strömmar för att läsa och skicka data eftersom det inte representerar anslutningen mellan en server och en klient.
importera java.net. InetAddress; importera java.net. ServerSocket; public class NetworkAppExample {public static void main (String args) kastar undantag {String host = "localhost"; int port = 10430; ServerSocket -server = ny ServerSocket (port, 50, InetAddress.getByName (värd)); }}
Steg 5. Start av loggserver
För loggning, skriv ut till konsolen att servern har startats.
importera java.net. InetAddress; importera java.net. ServerSocket; public class NetworkAppExample {public static void main (String args) kastar undantag {String host = "localhost"; int port = 10430; ServerSocket -server = ny ServerSocket (port, 50, InetAddress.getByName (värd)); System.out.println ("Server startad."); }}
Steg 6. Skapa en klient
Klienten är bunden till adressen och porten på en server och lyssnar efter paket (meddelanden) efter att anslutningen upprättats. I Java,
Uttag
representerar antingen en slutpunkt på klientsidan som är ansluten till servern eller en anslutning (från server) till klient och används för att kommunicera med parten i andra änden.
importera java.net. InetAddress; importera java.net. ServerSocket; importera java.net. Socket; public class NetworkAppExample {public static void main (String args) kastar undantag {String host = "localhost"; int port = 10430; ServerSocket -server = ny ServerSocket (port, 50, InetAddress.getByName (värd)); System.out.println ("Server startad."); Socket -klient = ny Socket (värd, port); }}
Steg 7. Logganslutningsförsök
För loggning, skriv ut till konsolen att anslutningen har försökt.
importera java.net. InetAddress; importera java.net. ServerSocket; importera java.net. Socket; public class NetworkAppExample {public static void main (String args) kastar undantag {String host = "localhost"; int port = 10430; ServerSocket -server = ny ServerSocket (port, 50, InetAddress.getByName (värd)); System.out.println ("Server startad."); Socket -klient = ny Socket (värd, port); System.out.println ("Ansluter till server …"); }}
Steg 8. Upprätta anslutning
Klienter kommer aldrig att ansluta om inte servern lyssnar efter och accepterar, med andra ord upprättar, anslutningar. I Java upprättas anslutningar med
acceptera()
metod av
ServerSocket
klass. Metoden blockerar körningen tills en klient ansluter.
importera java.net. InetAddress; importera java.net. ServerSocket; importera java.net. Socket; public class NetworkAppExample {public static void main (String args) kastar undantag {String host = "localhost"; int port = 10430; ServerSocket -server = ny ServerSocket (port, 50, InetAddress.getByName (värd)); System.out.println ("Server startad."); Socket -klient = ny Socket (värd, port); System.out.println ("Ansluter till server …"); Socket -anslutning = server.accept (); }}
Steg 9. Logga upprättad anslutning
För loggning, skriv ut till konsolen att anslutningen mellan server och klient har upprättats.
importera java.net. InetAddress; importera java.net. ServerSocket; importera java.net. Socket; public class NetworkAppExample {public static void main (String args) kastar undantag {String host = "localhost"; int port = 10430; ServerSocket -server = ny ServerSocket (port, 50, InetAddress.getByName (värd)); System.out.println ("Server startad."); Socket -klient = ny Socket (värd, port); System.out.println ("Ansluter till server …"); Socket -anslutning = server.accept (); System.out.println ("Anslutning upprättad."); }}
Steg 10. Förbered kommunikationsströmmar
Kommunikation sker via strömmar och i denna applikation måste råa strömmar från (anslutning från) server (till klient) och klient kopplas till antingen data- eller objektströmmar. Kom ihåg att båda parter måste använda samma strömtyp.
-
Dataströmmar
importera java.io. DataInputStream; importera java.io. DataOutputStream; importera java.net. InetAddress; importera java.net. ServerSocket; importera java.net. Socket; public class NetworkAppExample {public static void main (String args) kastar undantag {String host = "localhost"; int port = 10430; ServerSocket -server = ny ServerSocket (port, 50, InetAddress.getByName (värd)); System.out.println ("Server startad."); Socket -klient = ny Socket (värd, port); System.out.println ("Ansluter till server …"); Socket -anslutning = server.accept (); System.out.println ("Anslutning upprättad."); DataOutputStream clientOut = ny DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = ny DataInputStream (client.getInputStream ()); DataOutputStream serverOut = ny DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = ny DataInputStream (connection.getInputStream ()); }}
-
Objektströmmar
När flera objektströmmar används måste inmatningsströmmar initieras i samma ordning som utdataströmmar eftersom
ObjectOutputStream
skickar en rubrik till den andra parten och
ObjectInputStream
blockerar körning tills den läser rubriken.
importera java.io. ObjectInputStream; importera java.io. ObjectOutputStream; importera java.net. InetAddress; importera java.net. ServerSocket; importera java.net. Socket; public class NetworkAppExample {public static void main (String args) kastar undantag {String host = "localhost"; int port = 10430; ServerSocket -server = ny ServerSocket (port, 50, InetAddress.getByName (värd)); System.out.println ("Server startad."); Socket -klient = ny Socket (värd, port); System.out.println ("Ansluter till server …"); Socket -anslutning = server.accept (); System.out.println ("Anslutning upprättad."); ObjectOutputStream clientOut = nytt ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = nytt ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = nytt ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = nytt ObjectInputStream (connection.getInputStream ()); }}
Ordning som anges i koden ovan kan vara lättare att komma ihåg - initiera först utflöden och sedan inmatningsströmmar i samma ordning. En annan order för initialisering av objektströmmar är dock följande:
ObjectOutputStream clientOut = nytt ObjectOutputStream (client.getOutputStream ()); ObjectInputStream serverIn = nytt ObjectInputStream (connection.getInputStream ()); ObjectOutputStream serverOut = nytt ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = nytt ObjectInputStream (client.getInputStream ());
Steg 11. Logga in att kommunikationen är klar
För loggning, skriv ut till konsolen att kommunikationen är klar.
// kod utelämnad import java.net. InetAddress; importera java.net. ServerSocket; importera java.net. Socket; public class NetworkAppExample {public static void main (String args) kastar undantag {String host = "localhost"; int port = 10430; ServerSocket -server = ny ServerSocket (port, 50, InetAddress.getByName (värd)); System.out.println ("Server startad."); Socket -klient = ny Socket (värd, port); System.out.println ("Ansluter till server …"); Socket -anslutning = server.accept (); System.out.println ("Anslutning upprättad."); // kod utelämnad System.out.println ("Kommunikationen är klar."); }}
Steg 12. Skapa ett meddelande
I denna ansökan,
Hej världen
text skickas till servern antingen som
byte
eller
Sträng
. Deklarera en variabel av typen som beror på vilken ström som används. Använda sig av
byte
för dataströmmar och
Sträng
för objektströmmar.
-
Dataströmmar
Med hjälp av dataströmmar görs serialisering genom att omvandla objekt till primitiva datatyper eller a
Sträng
. I detta fall,
Sträng
konverteras till
byte
istället för att skriva med
writeBytes ()
metod för att visa hur det skulle göras med andra objekt, till exempel bilder eller andra filer.
importera java.io. DataInputStream; importera java.io. DataOutputStream; importera java.net. InetAddress; importera java.net. ServerSocket; importera java.net. Socket; public class NetworkAppExample {public static void main (String args) kastar undantag {String host = "localhost"; int port = 10430; ServerSocket -server = ny ServerSocket (port, 50, InetAddress.getByName (värd)); System.out.println ("Server startad."); Socket -klient = ny Socket (värd, port); System.out.println ("Ansluter till server …"); Socket -anslutning = server.accept (); System.out.println ("Anslutning upprättad."); DataOutputStream clientOut = ny DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = ny DataInputStream (client.getInputStream ()); DataOutputStream serverOut = ny DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = ny DataInputStream (connection.getInputStream ()); System.out.println ("Kommunikationen är klar."); byte messageOut = "Hej världen".getBytes (); }}
-
Objektströmmar
importera java.io. ObjectInputStream; importera java.io. ObjectOutputStream; importera java.net. InetAddress; importera java.net. ServerSocket; importera java.net. Socket; public class NetworkAppExample {public static void main (String args) kastar undantag {String host = "localhost"; int port = 10430; ServerSocket -server = ny ServerSocket (port, 50, InetAddress.getByName (värd)); System.out.println ("Server startad."); Socket -klient = ny Socket (värd, port); System.out.println ("Ansluter till server …"); Socket -anslutning = server.accept (); System.out.println ("Anslutning upprättad."); ObjectOutputStream clientOut = nytt ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = nytt ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = nytt ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = nytt ObjectInputStream (connection.getInputStream ()); System.out.println ("Kommunikationen är klar."); String messageOut = "Hej världen"; }}
Steg 13. Skicka meddelandet
Skriv data till utmatningsströmmen och spola strömmen för att säkerställa att data har skrivits helt.
-
Dataströmmar
Ett meddelandes längd måste skickas först så att den andra parten vet hur många byte det behöver läsa. Efter att längden har skickats som en primitiv heltalstyp kan byte skickas.
importera java.io. DataInputStream; importera java.io. DataOutputStream; importera java.net. InetAddress; importera java.net. ServerSocket; importera java.net. Socket; public class NetworkAppExample {public static void main (String args) kastar undantag {String host = "localhost"; int port = 10430; ServerSocket -server = ny ServerSocket (port, 50, InetAddress.getByName (värd)); System.out.println ("Server startad."); Socket -klient = ny Socket (värd, port); System.out.println ("Ansluter till server …"); Socket -anslutning = server.accept (); System.out.println ("Anslutning upprättad."); DataOutputStream clientOut = ny DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = ny DataInputStream (client.getInputStream ()); DataOutputStream serverOut = ny DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = ny DataInputStream (connection.getInputStream ()); System.out.println ("Kommunikationen är klar."); byte messageOut = "Hej världen".getBytes (); clientOut.writeInt (messageOut.length); clientOut.write (messageOut); clientOut.flush (); }}
-
Objektströmmar
importera java.io. ObjectInputStream; importera java.io. ObjectOutputStream; importera java.net. InetAddress; importera java.net. ServerSocket; importera java.net. Socket; public class NetworkAppExample {public static void main (String args) kastar undantag {String host = "localhost"; int port = 10430; ServerSocket -server = ny ServerSocket (port, 50, InetAddress.getByName (värd)); System.out.println ("Server startad."); Socket -klient = ny Socket (värd, port); System.out.println ("Ansluter till server …"); Socket -anslutning = server.accept (); System.out.println ("Anslutning upprättad."); ObjectOutputStream clientOut = nytt ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = nytt ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = nytt ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = nytt ObjectInputStream (connection.getInputStream ()); System.out.println ("Kommunikationen är klar."); String messageOut = "Hej världen"; clientOut.writeObject (messageOut); clientOut.flush (); }}
Steg 14. Loggskickat meddelande
För loggning, skriv ut till konsolen att meddelandet har skickats.
-
Dataströmmar
importera java.io. DataInputStream; importera java.io. DataOutputStream; importera java.net. InetAddress; importera java.net. ServerSocket; importera java.net. Socket; public class NetworkAppExample {public static void main (String args) kastar undantag {String host = "localhost"; int port = 10430; ServerSocket -server = ny ServerSocket (port, 50, InetAddress.getByName (värd)); System.out.println ("Server startad."); Socket -klient = ny Socket (värd, port); System.out.println ("Ansluter till server …"); Socket -anslutning = server.accept (); System.out.println ("Anslutning upprättad."); DataOutputStream clientOut = ny DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = ny DataInputStream (client.getInputStream ()); DataOutputStream serverOut = ny DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = ny DataInputStream (connection.getInputStream ()); System.out.println ("Kommunikationen är klar."); byte messageOut = "Hello World".getBytes (); clientOut.writeInt (messageOut.length); clientOut.write (messageOut); clientOut.flush (); System.out.println ("Meddelande skickat till servern:" + ny sträng (messageOut)); }}
-
Objektströmmar
importera java.io. ObjectInputStream; importera java.io. ObjectOutputStream; importera java.net. InetAddress; importera java.net. ServerSocket; importera java.net. Socket; public class NetworkAppExample {public static void main (String args) kastar undantag {String host = "localhost"; int port = 10430; ServerSocket -server = ny ServerSocket (port, 50, InetAddress.getByName (värd)); System.out.println ("Server startad."); Socket -klient = ny Socket (värd, port); System.out.println ("Ansluter till server …"); Socket -anslutning = server.accept (); System.out.println ("Anslutning upprättad."); ObjectOutputStream clientOut = nytt ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = nytt ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = nytt ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = nytt ObjectInputStream (connection.getInputStream ()); System.out.println ("Kommunikationen är klar."); String messageOut = "Hej världen"; clientOut.writeObject (messageOut); clientOut.flush (); System.out.println ("Meddelande skickat till servern:" + messageOut); }}
Steg 15. Läs meddelandet
Läs data från inmatningsströmmen och konvertera den. Eftersom vi vet exakt vilken typ av skickad data, kommer vi antingen att skapa en
Sträng
från
byte
eller gjutna
Objekt
till
Sträng
utan att kontrollera, beroende på vilken ström som används.
-
Dataströmmar
Eftersom längden skickades först och byte efteråt måste avläsningen göras i samma ordning. Om längden är noll finns det inget att läsa. Objekt avserialiseras när byte konverteras tillbaka till en instans, i det här fallet, av
Sträng
importera java.io. DataInputStream; importera java.io. DataOutputStream; importera java.net. InetAddress; importera java.net. ServerSocket; importera java.net. Socket; public class NetworkAppExample {public static void main (String args) kastar undantag {String host = "localhost"; int port = 10430; ServerSocket -server = ny ServerSocket (port, 50, InetAddress.getByName (värd)); System.out.println ("Server startad."); Socket -klient = ny Socket (värd, port); System.out.println ("Ansluter till server …"); Socket -anslutning = server.accept (); System.out.println ("Anslutning upprättad."); DataOutputStream clientOut = ny DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = ny DataInputStream (client.getInputStream ()); DataOutputStream serverOut = ny DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = ny DataInputStream (connection.getInputStream ()); System.out.println ("Kommunikationen är klar."); byte messageOut = "Hello World".getBytes (); clientOut.writeInt (messageOut.length); clientOut.write (messageOut); clientOut.flush (); System.out.println ("Meddelande skickat till servern:" + ny sträng (messageOut)); int length = serverIn.readInt (); if (längd> 0) {byte meddelandeIn = ny byte [längd]; serverIn.readFully (messageIn, 0, messageIn.length); }}}
-
Objektströmmar
importera java.io. ObjectInputStream; importera java.io. ObjectOutputStream; importera java.net. InetAddress; importera java.net. ServerSocket; importera java.net. Socket; public class NetworkAppExample {public static void main (String args) kastar undantag {String host = "localhost"; int port = 10430; ServerSocket -server = ny ServerSocket (port, 50, InetAddress.getByName (värd)); System.out.println ("Server startad."); Socket -klient = ny Socket (värd, port); System.out.println ("Ansluter till server …"); Socket -anslutning = server.accept (); System.out.println ("Anslutning upprättad."); ObjectOutputStream clientOut = nytt ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = nytt ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = nytt ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = nytt ObjectInputStream (connection.getInputStream ()); System.out.println ("Kommunikationen är klar."); String messageOut = "Hej världen"; clientOut.writeObject (messageOut); clientOut.flush (); System.out.println ("Meddelande skickat till servern:" + messageOut); String messageIn = (String) serverIn.readObject (); }}
Steg 16. Logga läsmeddelande
För loggning, skriv ut till konsolen att meddelandet har mottagits och skriv ut dess innehåll.
-
Dataströmmar
importera java.io. DataInputStream; importera java.io. DataOutputStream; importera java.net. InetAddress; importera java.net. ServerSocket; importera java.net. Socket; public class NetworkAppExample {public static void main (String args) kastar undantag {String host = "localhost"; int port = 10430; ServerSocket -server = ny ServerSocket (port, 50, InetAddress.getByName (värd)); System.out.println ("Server startad."); Socket -klient = ny Socket (värd, port); System.out.println ("Ansluter till server …"); Socket -anslutning = server.accept (); System.out.println ("Anslutning upprättad."); DataOutputStream clientOut = ny DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = ny DataInputStream (client.getInputStream ()); DataOutputStream serverOut = ny DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = ny DataInputStream (connection.getInputStream ()); System.out.println ("Kommunikationen är klar."); byte messageOut = "Hello World".getBytes (); clientOut.writeInt (messageOut.length); clientOut.write (messageOut); clientOut.flush (); System.out.println ("Meddelande skickat till servern:" + ny sträng (messageOut)); int length = serverIn.readInt (); if (längd> 0) {byte meddelandeIn = ny byte [längd]; serverIn.readFully (messageIn, 0, messageIn.length); System.out.println ("Meddelande mottaget från klient:" + ny sträng (messageIn)); }}}
-
Objektströmmar
importera java.io. ObjectInputStream; importera java.io. ObjectOutputStream; importera java.net. InetAddress; importera java.net. ServerSocket; importera java.net. Socket; public class NetworkAppExample {public static void main (String args) kastar undantag {String host = "localhost"; int port = 10430; ServerSocket -server = ny ServerSocket (port, 50, InetAddress.getByName (värd)); System.out.println ("Server startad."); Socket -klient = ny Socket (värd, port); System.out.println ("Ansluter till server …"); Socket -anslutning = server.accept (); System.out.println ("Anslutning upprättad."); ObjectOutputStream clientOut = nytt ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = nytt ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = nytt ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = nytt ObjectInputStream (connection.getInputStream ()); System.out.println ("Kommunikationen är klar."); String messageOut = "Hej världen"; clientOut.writeObject (messageOut); clientOut.flush (); System.out.println ("Meddelande skickat till servern:" + messageOut); String messageIn = (String) serverIn.readObject (); System.out.println ("Meddelande mottaget från klient:" + messageIn); }}
Steg 17. Koppla bort anslutningarna
Anslutningen kopplas bort när en part stänger sina strömmar. I Java stängs också tillhörande uttag och ingångsström genom att stänga utströmmen. När en part i andra änden upptäcker att anslutningen är död, måste den också stänga sin utström för att förhindra minnesläckage.
// kod utelämnad import java.net. InetAddress; importera java.net. ServerSocket; importera java.net. Socket; public class NetworkAppExample {public static void main (String args) kastar undantag {String host = "localhost"; int port = 10430; ServerSocket -server = ny ServerSocket (port, 50, InetAddress.getByName (värd)); System.out.println ("Server startad."); Socket -klient = ny Socket (värd, port); System.out.println ("Ansluter till server …"); Socket -anslutning = server.accept (); System.out.println ("Anslutning upprättad."); // kod utelämnad System.out.println ("Kommunikationen är klar."); // kod utelämnad clientOut.close (); serverOut.close (); }}
Steg 18. Loggkoppling
För loggning har anslutningarna för utskrift till konsolen kopplats bort.
// kod utelämnad import java.net. InetAddress; importera java.net. ServerSocket; importera java.net. Socket; public class NetworkAppExample {public static void main (String args) kastar undantag {String host = "localhost"; int port = 10430; ServerSocket -server = ny ServerSocket (port, 50, InetAddress.getByName (värd)); System.out.println ("Server startad."); Socket -klient = ny Socket (värd, port); System.out.println ("Ansluter till server …"); Socket -anslutning = server.accept (); System.out.println ("Anslutning upprättad."); // kod utelämnad System.out.println ("Kommunikationen är klar."); // kod utelämnad clientOut.close (); serverOut.close (); System.out.println ("Anslutningar stängda."); }}
Steg 19. Avsluta servern
Anslutningarna är frånkopplade, men servern är fortfarande igång. Som
ServerSocket
är inte associerad med någon ström, måste det uttryckligen stängas genom att ringa
stänga()
metod.
// kod utelämnad import java.net. InetAddress; importera java.net. ServerSocket; importera java.net. Socket; public class NetworkAppExample {public static void main (String args) kastar undantag {String host = "localhost"; int port = 10430; ServerSocket -server = ny ServerSocket (port, 50, InetAddress.getByName (värd)); System.out.println ("Server startad."); Socket -klient = ny Socket (värd, port); System.out.println ("Ansluter till server …"); Socket -anslutning = server.accept (); System.out.println ("Anslutning upprättad."); // kod utelämnad System.out.println ("Kommunikationen är klar."); // kod utelämnad clientOut.close (); serverOut.close (); System.out.println ("Anslutningar stängda."); server.close (); }}
Steg 20. Avslutning av loggserver
För loggning har utskriften till konsolservern avslutats.
// kod utelämnad import java.net. InetAddress; importera java.net. ServerSocket; importera java.net. Socket; public class NetworkAppExample {public static void main (String args) kastar undantag {String host = "localhost"; int port = 10430; ServerSocket -server = ny ServerSocket (port, 50, InetAddress.getByName (värd)); System.out.println ("Server startad."); Socket -klient = ny Socket (värd, port); System.out.println ("Ansluter till server …"); Socket -anslutning = server.accept (); System.out.println ("Anslutning upprättad."); // kod utelämnad System.out.println ("Kommunikationen är klar."); // kod utelämnad clientOut.close (); serverOut.close (); System.out.println ("Anslutningar stängda."); server.close (); System.out.println ("Server avslutad."); }}
Steg 21. Kompilera och kör
Loggning gjorde det möjligt för oss att veta om programmet lyckades eller inte. Förväntad produktion:
Servern startade. Ansluter till server … Anslutning upprättad. Kommunikationen är klar. Meddelande skickat till servern: Hello World Meddelande mottaget från klienten: Hello World Connections stängda. Servern har avslutats.
Om din utmatning inte är som den ovan, vilket osannolikt kommer att hända, finns det några lösningar:
-
Om utgången stannar vid linjen
Kontakt etablerad.
och objektströmmar används, spola var och en
ObjectOutputStream
- omedelbart efter initialiseringen eftersom rubriker av någon anledning inte skickades.
-
Om utskriften skrivs ut
java.net. BindException: Adress som redan används
- välj ett annat portnummer eftersom det angivna redan används.
Tips
- Anslutning till en server i ett annat nätverk görs genom att ansluta till den externa IP -adressen för en enhet som kör servern som har en vidarebefordrad port.
- Anslutning till en server i samma nätverk görs genom att antingen ansluta till den privata IP -adressen för en enhet som kör servern eller vidarebefordra en port och ansluta till enhetens externa IP -adress.
- Det finns programvara, till exempel Hamachi, som gör det möjligt att ansluta till servern i ett annat nätverk utan att vidarebefordra en port, men det kräver installation av programvaran på båda enheterna.
Exempel
Nätverksapplikationer som använder blockerande input/output måste använda trådar. Följande exempel visar en minimalistisk server- och klientimplementering med trådar. Nätverkskoden är i huvudsak densamma som i artikeln förutom att några utdrag synkroniserades, flyttades till trådar och undantag hanteras.
Server.java
importera java.io. IOException; importera java.net. InetAddress; importera java.net. ServerSocket; importera java.net. SocketException; importera java.net. UnknownHostException; importera java.util. ArrayList; importera java.util. Collections; importera java.util. List; /*** Klassen {@code Server} representerar en server slutpunkt i ett nätverk. {@code Server} en gång bunden till en viss IP * -adress och port, upprättar anslutningar med klienter och kan kommunicera med dem eller koppla bort dem. *
* Den här klassen är trådsäker. * * @version 1.0 * @see Client * @see Connection */ public class Server implementerar Runnable {private ServerSocket server; privat lista
anslutningar; privat trådtråd; private final Object connectionsLock = new Object (); /** * Konstruerar en {@code Server} som interagerar med klienter på det angivna värdnamnet och porten med den angivna * begärda maximala längden på en kö av inkommande klienter. * * @param värd Värdadress som ska användas. * @param -port Portnummer som ska användas. * @param backlog Begärde maximal längd på kön för inkommande klienter. * @kastar NetworkException Om ett fel uppstår när en server startas. */ public Server (String host, int port, int backlog) kastar NetworkException {try {server = new ServerSocket (port, backlog, InetAddress.getByName (host)); } catch (UnknownHostException e) {throw new NetworkException ("Värdnamn kunde inte lösas:" + värd, e); } catch (IllegalArgumentException e) {throw new NetworkException ("Portnummer måste vara mellan 0 och 65535 (inklusive):" + port); } catch (IOException e) {throw new NetworkException ("Servern kunde inte startas.", e); } anslutningar = Collections.synchronizedList (ny ArrayList ()); tråd = ny tråd (detta); thread.start (); } /*** Konstruerar en {@code Server} som interagerar med klienter på det angivna värdnamnet och porten. * * @param värd Värdadress att binda. * @param -port Portnummer som ska bindas. * @throws NetworkException Om det uppstår fel när en server startas. */ public Server (String -värd, int -port) kastar NetworkException {detta (värd, port, 50); } /*** Lyssnar på, accepterar och registrerar inkommande anslutningar från klienter. */ @Override public void run () {while (! Server.isClosed ()) {try {connections.add (new Connection (server.accept ())); } catch (SocketException e) {if (! e.getMessage (). är lika med ("Socket stängd")) {e.printStackTrace (); }} catch (NetworkException | IOException e) {e.printStackTrace (); }}} /*** Skickar data till alla registrerade klienter. * * @param data Data att skicka. * @throws IllegalStateException Om du försöker skriva data när servern är offline. * @throws IllegalArgumentException Om data som ska skickas är noll. */ public void broadcast (Objektdata) {if (server.isClosed ()) {kasta ny IllegalStateException ("Data skickas inte, servern är offline."); } if (data == null) {kasta ny IllegalArgumentException ("null data"); } synkroniserad (connectionsLock) {för (Anslutningsanslutning: anslutningar) {prova {connection.send (data); System.out.println ("Data skickades till klienten framgångsrikt."); } catch (NetworkException e) {e.printStackTrace (); }}}} /*** Skickar ett frånkopplingsmeddelande och kopplar bort angiven klient. * * @param -anslutning Klienten kopplar bort. * @kastar NetworkException Om ett fel uppstår när anslutningen stängs. */ public void disconnect (Connection connection) kastar NetworkException {if (connections.remove (anslutning)) {connection.close (); }} /*** Skickar ett frånkopplingsmeddelande till alla klienter, kopplar bort dem och avslutar servern. */ public void close () kastar NetworkException {synchronized (connectionsLock) {för (Connection connection: connections) {try {connection.close (); } catch (NetworkException e) {e.printStackTrace (); }}} connections.clear (); prova {server.close (); } catch (IOException e) {kasta nytt NetworkException ("Fel vid stängning av server."); } äntligen {thread.interrupt (); }} /*** Returnerar om servern är online eller inte. * * @return True om servern är online. Falskt, annars. */ public boolean isOnline () {return! server.isClosed (); } /*** Returnerar en rad registrerade klienter. */ public Connection getConnections () {synchronized (connectionsLock) {return connections.toArray (new Connection [connections.size ()]); }}}
Client.java
importera java.io. IOException; importera java.net. Socket; importera java.net. UnknownHostException; /*** Klassen {@code Client} representerar en klients slutpunkt i ett nätverk. {@code Client}, när den väl är ansluten till en viss * server, kan garanterat bara kommunicera med servern. Om andra klienter får data * beror på serverimplementeringen. *
* Den här klassen är trådsäker. * * @version 1.0 * @see Server * @see Connection */ public class Client {privat anslutningsanslutning; /*** Konstruerar en {@code Client} som är ansluten till servern på den angivna värden och porten. * * @param värd Värdadress att binda. * @param -port Portnummer som ska bindas. * @kastar NetworkException Om ett fel uppstår när en server startas. */ public Client (String host, int port) kastar NetworkException {try {connection = new Connection (new Socket (host, port)); } catch (UnknownHostException e) {throw new NetworkException ("Värdnamn kunde inte lösas:" + värd, e); } catch (IllegalArgumentException e) {throw new NetworkException ("Portnummer måste vara mellan 0 och 65535 (inklusive):" + port); } catch (IOException e) {throw new NetworkException ("Servern kunde inte startas.", e); }} /*** Skickar data till den andra parten. * * @param data Data att skicka. * @kastar NetworkException Om skrivning till utdataström misslyckas. * @throws IllegalStateException Om du försöker skriva data när anslutningen stängs. * @throws IllegalArgumentException Om data som ska skickas är noll. * @throws UnsupportedOperationException Om datatyp som inte stöds ska skickas. */ public void send (objektdata) kastar NetworkException {connection.send (data); } /*** Skickar ett frånkopplingsmeddelande till och stänger anslutningen till servern. */ public void close () kastar NetworkException {connection.close (); } /*** Returnerar om klienten är ansluten till servern eller inte. * * @return True om klienten är ansluten. Falskt, annars. */ public boolean isOnline () {returanslutning.isConnected (); } /*** Returnerar instansen {@link Connection} för klienten. */ public Connection getConnection () {returanslutning; }}
Anslutning. Java
importera java.io. DataInputStream; importera java.io. DataOutputStream; importera java.io. IOException; importera java.net. Socket; importera java.net. SocketException; /** * Klassen {@code Connection} representerar antingen en anslutning från server till klient eller en slutpunkt för klienten i ett nätverk * {@code Connection}, när den är ansluten, kan utbyta data med andra parter eller parter, beroende på på en server * -implementering. *
* Den här klassen är trådsäker. * * @version 1.0 * @see Server * @see Client */ public class Anslutning implementerar Runnable {private Socket socket; privat DataOutputStream ut; privat DataInputStream i; privat trådtråd; privat slutligt objekt writeLock = nytt objekt (); privat slutligt objekt readLock = nytt objekt (); /*** Konstruerar {@code Connection} med hjälp av strömmar från en angiven {@link Socket}. * * @param -uttag Socket för att hämta strömmarna från.*/ public Connection (Socket socket) kastar NetworkException {if (socket == null) {kasta nytt IllegalArgumentException ("null socket"); } this.socket = socket; prova {out = new DataOutputStream (socket.getOutputStream ()); } catch (IOException e) {throw new NetworkException ("Det gick inte att komma åt utmatningsströmmen.", e); } prova {in = new DataInputStream (socket.getInputStream ()); } catch (IOException e) {throw new NetworkException ("Det gick inte att komma åt inmatningsström.", e); } tråd = ny tråd (detta); thread.start (); } /*** Läser meddelanden medan anslutningen till den andra parten lever. */ @Override public void run () {while (! Socket.isClosed ()) {try {int identifier; byte byte; synkroniserad (readLock) {identifier = in.readInt (); int längd = in.readInt (); if (längd> 0) {byte = ny byte [längd]; in.readFully (byte, 0, bytes.length); } annat {fortsätt; }} switch (identifierare) {case Identifier. INTERNAL: String command = new String (bytes); if (command.equals ("koppla bort")) {if (! socket.isClosed ()) {System.out.println ("Avkopplingspaket mottaget."); prova {close (); } catch (NetworkException e) {return; } } } ha sönder; case Identifier. TEXT: System.out.println ("Meddelande mottaget:" + ny sträng (byte)); ha sönder; standard: System.out.println ("Okänd data mottagen."); }} catch (SocketException e) {if (! e.getMessage (). är lika med ("Socket stängd")) {e.printStackTrace (); }} catch (IOException e) {e.printStackTrace (); }}} /*** Skickar data till den andra parten. * * @param data Data att skicka. * @kastar NetworkException Om skrivning till utdataström misslyckas. * @throws IllegalStateException Om du försöker skriva data när anslutningen stängs. * @throws IllegalArgumentException Om data som ska skickas är noll. * @throws UnsupportedOperationException Om datatyp som inte stöds ska skickas. */ public void send (Objektdata) kastar NetworkException {if (socket.isClosed ()) {kasta ny IllegalStateException ("Data skickas inte, anslutningen stängs."); } if (data == null) {kasta ny IllegalArgumentException ("null data"); } int -identifierare; byte byte; if (datainstans av sträng) {identifier = Identifier. TEXT; byte = ((String) data).getBytes (); } else {throw new UnsupportedOperationException ("Datatyp som inte stöds:" + data.getClass ()); } prova {synchronized (writeLock) {out.writeInt (identifierare); out.writeInt (bytes.length); out.write (byte); out.flush (); }} catch (IOException e) {throw new NetworkException ("Data kunde inte skickas.", e); }} /*** Skickar ett frånkopplingsmeddelande till och stänger anslutningen med den andra parten. */ public void close () kastar NetworkException {if (socket.isClosed ()) {throw new IllegalStateException ("Connection is already closed."); } prova {byte meddelande = "koppla bort".getBytes (); synkroniserad (writeLock) {out.writeInt (Identifier. INTERNAL); out.writeInt (meddelande.längd); out.write (meddelande); out.flush (); }} catch (IOException e) {System.out.println ("Det gick inte att skicka frånkopplingsmeddelande."); } prova {synchronized (writeLock) {out.close (); }} catch (IOException e) {throw new NetworkException ("Fel vid anslutning.", e); } äntligen {thread.interrupt (); }} /*** Returnerar om anslutningen till den andra parten lever eller inte. * * @return Sann om anslutningen är levande. Falskt, annars. */ public boolean isConnected () {return! socket.isClosed (); }}
Identifier.java
/** * Klassen {@code Identifier} innehåller konstanter som används av {@link Connection} för att serialisera och deserialisera data * som skickas över nätverket. * * @version 1.0 * @see Connection * / public final class Identifier { / ** * Identifier för interna meddelanden. */ public static final int INTERNAL = 1; /*** Identifierare för textmeddelanden. */ public static final int TEXT = 2; }
NetworkException.java
/*** Klassen {@code NetworkException} indikerar ett fel relaterat till nätverket. * / public class NetworkException utvidgar undantag { / *** Konstruerar en {@code NetworkException} med {@code null} som meddelande. * / public NetworkException () {} / *** Konstruerar en {@code NetworkException} med det angivna meddelandet. * * @param -meddelande Ett meddelande för att beskriva fel. */ public NetworkException (strängmeddelande) {super (meddelande); } /*** Konstruerar en {@code NetworkException} med det angivna meddelandet och orsaken. * * @param -meddelande Ett meddelande för att beskriva fel. * @param orsak En orsak till fel. */ public NetworkException (strängmeddelande, orsak som kan kastas) {super (meddelande, orsak); } /*** Konstruerar en {@code NetworkException} med den angivna orsaken. * * @param orsak En orsak till fel. */ public NetworkException (orsak som kan kastas) {super (orsak); }}
UsageExample.java
/*** Klassen {@code UsageExample} visar användningen av {@link Server} och {@link Client}. I dessa exempel används * {@link Thread#sleep (long)} för att säkerställa att varje segment körs eftersom snabb start och stängning gör att vissa * segment inte körs. * * @version 1.0 * @see Server * @see Client */ public class UsageExample {public static void main (String args) kastar undantag {String host = "localhost"; int port = 10430; Server server = ny server (värd, port); Klientklient = ny klient (värd, port); Tråd. Sover (100L); client.send ("Hej."); server.broadcast ("Hej, fella!"); Tråd. Sover (100L); server.disconnect (server.getConnections () [0]); // eller client.close () för att koppla bort från server.close () på klientsidan; }}