Java Language
Netwerken
Zoeken…
Syntaxis
- nieuwe Socket ("localhost", 1234); // Maakt verbinding met een server op adres "localhost" en poort 1234
- nieuwe SocketServer ("localhost", 1234); // Maakt een socket-server die kan luisteren naar nieuwe sockets op adres localhost en poort 1234
- socketServer.accept (); // Accepteert een nieuw Socket-object dat kan worden gebruikt om met de client te communiceren
Basis client- en servercommunicatie met behulp van een socket
Server: Start en wacht op inkomende verbindingen
//Open a listening "ServerSocket" on port 1234.
ServerSocket serverSocket = new ServerSocket(1234);
while (true) {
// Wait for a client connection.
// Once a client connected, we get a "Socket" object
// that can be used to send and receive messages to/from the newly
// connected client
Socket clientSocket = serverSocket.accept();
// Here we'll add the code to handle one specific client.
}
Server: clients afhandelen
We behandelen elke client in een afzonderlijke thread, zodat meerdere clients tegelijkertijd met de server kunnen communiceren. Deze techniek werkt prima zolang het aantal clients laag is (<< 1000 clients, afhankelijk van de OS-architectuur en de verwachte belasting van elke thread).
new Thread(() -> {
// Get the socket's InputStream, to read bytes from the socket
InputStream in = clientSocket.getInputStream();
// wrap the InputStream in a reader so you can read a String instead of bytes
BufferedReader reader = new BufferedReader(
new InputStreamReader(in, StandardCharsets.UTF_8));
// Read text from the socket and print line by line
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}).start();
Client: maak verbinding met de server en verzend een bericht
// 127.0.0.1 is the address of the server (this is the localhost address; i.e.
// the address of our own machine)
// 1234 is the port that the server will be listening on
Socket socket = new Socket("127.0.0.1", 1234);
// Write a string into the socket, and flush the buffer
OutputStream outStream = socket.getOutputStream();
PrintWriter writer = new PrintWriter(
new OutputStreamWriter(outStream, StandardCharsets.UTF_8));
writer.println("Hello world!");
writer.flush();
Contactdozen sluiten en uitzonderingen bij gebruik
In de bovenstaande voorbeelden zijn enkele dingen weggelaten om ze gemakkelijker leesbaar te maken.
Net als bestanden en andere externe bronnen, is het belangrijk dat we het besturingssysteem vertellen wanneer we hiermee klaar zijn. Wanneer we klaar zijn met een socket, roept u
socket.close()
aan om deze goed te sluiten.Sockets verwerken I / O-bewerkingen (invoer / uitvoer) die afhankelijk zijn van verschillende externe factoren. Wat bijvoorbeeld als de andere kant plotseling verbreekt? Wat als er een netwerkfout is? Deze dingen zijn buiten onze controle. Dit is de reden waarom veel
IOException
uitzonderingen kunnen veroorzaken, met nameIOException
.
Een completere code voor de client zou daarom zoiets zijn:
// "try-with-resources" will close the socket once we leave its scope
try (Socket socket = new Socket("127.0.0.1", 1234)) {
OutputStream outStream = socket.getOutputStream();
PrintWriter writer = new PrintWriter(
new OutputStreamWriter(outStream, StandardCharsets.UTF_8));
writer.println("Hello world!");
writer.flush();
} catch (IOException e) {
//Handle the error
}
Basic Server en Client - volledige voorbeelden
Server:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
public class Server {
public static void main(String args[]) {
try (ServerSocket serverSocket = new ServerSocket(1234)) {
while (true) {
// Wait for a client connection.
Socket clientSocket = serverSocket.accept();
// Create and start a thread to handle the new client
new Thread(() -> {
try {
// Get the socket's InputStream, to read bytes
// from the socket
InputStream in = clientSocket.getInputStream();
// wrap the InputStream in a reader so you can
// read a String instead of bytes
BufferedReader reader = new BufferedReader(
new InputStreamReader(in, StandardCharsets.UTF_8));
// Read from the socket and print line by line
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
catch (IOException e) {
e.printStackTrace();
} finally {
// This finally block ensures the socket is closed.
// A try-with-resources block cannot be used because
// the socket is passed into a thread, so it isn't
// created and closed in the same block
try {
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
}
catch (IOException e) {
e.printStackTrace();
}
}
}
Cliënt:
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
public class Client {
public static void main(String args[]) {
try (Socket socket = new Socket("127.0.0.1", 1234)) {
// We'll reach this code once we've connected to the server
// Write a string into the socket, and flush the buffer
OutputStream outStream = socket.getOutputStream();
PrintWriter writer = new PrintWriter(
new OutputStreamWriter(outStream, StandardCharsets.UTF_8));
writer.println("Hello world!");
writer.flush();
} catch (IOException e) {
// Exception should be handled.
e.printStackTrace();
}
}
}
TrustStore en KeyStore laden vanuit InputStream
public class TrustLoader {
public static void main(String args[]) {
try {
//Gets the inputstream of a a trust store file under ssl/rpgrenadesClient.jks
//This path refers to the ssl folder in the jar file, in a jar file in the same directory
//as this jar file, or a different directory in the same directory as the jar file
InputStream stream = TrustLoader.class.getResourceAsStream("/ssl/rpgrenadesClient.jks");
//Both trustStores and keyStores are represented by the KeyStore object
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
//The password for the trustStore
char[] trustStorePassword = "password".toCharArray();
//This loads the trust store into the object
trustStore.load(stream, trustStorePassword);
//This is defining the SSLContext so the trust store will be used
//Getting default SSLContext to edit.
SSLContext context = SSLContext.getInstance("SSL");
//TrustMangers hold trust stores, more than one can be added
TrustManagerFactory factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
//Adds the truststore to the factory
factory.init(trustStore);
//This is passed to the SSLContext init method
TrustManager[] managers = factory.getTrustManagers();
context.init(null, managers, null);
//Sets our new SSLContext to be used.
SSLContext.setDefault(context);
} catch (KeyStoreException | IOException | NoSuchAlgorithmException
| CertificateException | KeyManagementException ex) {
//Handle error
ex.printStackTrace();
}
}
}
Het inleiden van een KeyStore werkt hetzelfde, behalve dat elk woord Trust
in een objectnaam wordt vervangen door Key
. Bovendien moet de KeyManager[]
worden doorgegeven aan het eerste argument van SSLContext.init
. Dat is SSLContext.init(keyMangers, trustMangers, null)
Socketvoorbeeld - een webpagina lezen met een eenvoudige socket
import java.io.*;
import java.net.Socket;
public class Main {
public static void main(String[] args) throws IOException {//We don't handle Exceptions in this example
//Open a socket to stackoverflow.com, port 80
Socket socket = new Socket("stackoverflow.com",80);
//Prepare input, output stream before sending request
OutputStream outStream = socket.getOutputStream();
InputStream inStream = socket.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inStream));
PrintWriter writer = new PrintWriter(new BufferedOutputStream(outStream));
//Send a basic HTTP header
writer.print("GET / HTTP/1.1\nHost:stackoverflow.com\n\n");
writer.flush();
//Read the response
System.out.println(readFully(reader));
//Close the socket
socket.close();
}
private static String readFully(Reader in) {
StringBuilder sb = new StringBuilder();
int BUFFER_SIZE=1024;
char[] buffer = new char[BUFFER_SIZE]; // or some other size,
int charsRead = 0;
while ( (charsRead = rd.read(buffer, 0, BUFFER_SIZE)) != -1) {
sb.append(buffer, 0, charsRead);
}
}
}
U zou een antwoord moeten krijgen dat begint met HTTP/1.1 200 OK
, wat een normaal HTTP-antwoord aangeeft, gevolgd door de rest van de HTTP-header, gevolgd door de onbewerkte webpagina in HTML-vorm.
Merk op dat de methode readFully()
belangrijk is om een voortijdige EOF-uitzondering te voorkomen. De laatste regel van de webpagina mist mogelijk een terugkeer, om het einde van de regel aan te geven, dan zal readLine()
klagen, dus men moet het met de hand lezen of gebruik maken van hulpprogramma's van Apache commons-io IOUtils
Dit voorbeeld is bedoeld als een eenvoudige demonstratie van verbinding maken met een bestaande bron met behulp van een socket. Het is geen praktische manier om webpagina's te openen. Als u een webpagina wilt openen met Java, kunt u het beste een bestaande HTTP-clientbibliotheek gebruiken, zoals Apache's HTTP Client of Google's HTTP Client
Basic Client / Server Communication using UDP (Datagram)
Client.java
import java.io.*;
import java.net.*;
public class Client{
public static void main(String [] args) throws IOException{
DatagramSocket clientSocket = new DatagramSocket();
InetAddress address = InetAddress.getByName(args[0]);
String ex = "Hello, World!";
byte[] buf = ex.getBytes();
DatagramPacket packet = new DatagramPacket(buf,buf.length, address, 4160);
clientSocket.send(packet);
}
}
In dit geval geven we het adres van de server door via een argument ( args[0]
). De poort die we gebruiken is 4160.
Server.java
import java.io.*;
import java.net.*;
public class Server{
public static void main(String [] args) throws IOException{
DatagramSocket serverSocket = new DatagramSocket(4160);
byte[] rbuf = new byte[256];
DatagramPacket packet = new DatagramPacket(rbuf, rbuf.length);
serverSocket.receive(packet);
String response = new String(packet.getData());
System.out.println("Response: " + response);
}
}
Geef aan de serverkant een DatagramSocket aan op dezelfde poort waarnaar we ons bericht hebben gestuurd (4160) en wacht op een antwoord.
multicasting
Multicasting is een type Datagram-socket. In tegenstelling tot gewone Datagrams, behandelt Multicasting niet elke client afzonderlijk, maar stuurt het het naar één IP-adres en krijgen alle ingeschreven clients het bericht.
Voorbeeldcode voor een serverzijde:
public class Server {
private DatagramSocket serverSocket;
private String ip;
private int port;
public Server(String ip, int port) throws SocketException, IOException{
this.ip = ip;
this.port = port;
// socket used to send
serverSocket = new DatagramSocket();
}
public void send() throws IOException{
// make datagram packet
byte[] message = ("Multicasting...").getBytes();
DatagramPacket packet = new DatagramPacket(message, message.length,
InetAddress.getByName(ip), port);
// send packet
serverSocket.send(packet);
}
public void close(){
serverSocket.close();
}
}
Voorbeeldcode voor een client:
public class Client {
private MulticastSocket socket;
public Client(String ip, int port) throws IOException {
// important that this is a multicast socket
socket = new MulticastSocket(port);
// join by ip
socket.joinGroup(InetAddress.getByName(ip));
}
public void printMessage() throws IOException{
// make datagram packet to recieve
byte[] message = new byte[256];
DatagramPacket packet = new DatagramPacket(message, message.length);
// recieve the packet
socket.receive(packet);
System.out.println(new String(packet.getData()));
}
public void close(){
socket.close();
}
}
Code voor het uitvoeren van de server:
public static void main(String[] args) {
try {
final String ip = args[0];
final int port = Integer.parseInt(args[1]);
Server server = new Server(ip, port);
server.send();
server.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
Code voor het runnen van een client:
public static void main(String[] args) {
try {
final String ip = args[0];
final int port = Integer.parseInt(args[1]);
Client client = new Client(ip, port);
client.printMessage();
client.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
Voer eerst de client uit: de client moet zich abonneren op het IP-adres voordat hij pakketten kan ontvangen. Als u de server start en de methode send()
aanroept en vervolgens een client maakt (& call printMessage()
). Er gebeurt niets omdat de client verbinding heeft gemaakt nadat het bericht was verzonden.
SSL-verificatie tijdelijk uitschakelen (voor testdoeleinden)
Soms is de SSL-certificaatketen in een ontwikkel- of testomgeving (nog) niet volledig vastgesteld.
Om door te gaan met ontwikkelen en testen, kunt u SSL-verificatie programmatisch uitschakelen door een "vertrouwende" trustmanager te installeren:
try {
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}
};
// Install the all-trusting trust manager
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
// Create all-trusting host name verifier
HostnameVerifier allHostsValid = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
// Install the all-trusting host verifier
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
} catch (NoSuchAlgorithmException | KeyManagementException e) {
e.printStackTrace();
}
Een bestand downloaden via Kanaal
Als het bestand al bestaat, wordt het overschreven!
String fileName = "file.zip"; // name of the file
String urlToGetFrom = "http://www.mywebsite.com/"; // URL to get it from
String pathToSaveTo = "C:\\Users\\user\\"; // where to put it
//If the file already exists, it will be overwritten!
//Opening OutputStream to the destination file
try (ReadableByteChannel rbc =
Channels.newChannel(new URL(urlToGetFrom + fileName).openStream()) ) {
try ( FileChannel channel =
new FileOutputStream(pathToSaveTo + fileName).getChannel(); ) {
channel.transferFrom(rbc, 0, Long.MAX_VALUE);
}
catch (FileNotFoundException e) { /* Output directory not found */ }
catch (IOException e) { /* File IO error */ }
}
catch (MalformedURLException e) { /* URL is malformed */ }
catch (IOException e) { /* IO error connecting to website */ }
Notes
- Laat de opvangblokken niet leeg!
- Controleer in geval van een fout of het externe bestand bestaat
- Dit is een blokkeerbewerking die bij grote bestanden lang kan duren