Java Language
nätverk
Sök…
Syntax
- new Socket ("localhost", 1234); // Ansluts till en server på adressen "localhost" och port 1234
- ny SocketServer ("localhost", 1234); // Skapar en socket-server som kan lyssna på nya uttag på adressen localhost och port 1234
- socketServer.accept (); // Accepterar ett nytt Socket-objekt som kan användas för att kommunicera med klienten
Grundläggande klient- och serverkommunikation med hjälp av ett uttag
Server: Starta och vänta på inkommande anslutningar
//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: Hantera klienter
Vi hanterar varje klient i en separat tråd så att flera klienter kan interagera med servern samtidigt. Den här tekniken fungerar bra så länge antalet klienter är lågt (<< 1000 klienter, beroende på OS-arkitekturen och den förväntade belastningen på varje tråd).
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();
Klient: Anslut till servern och skicka ett meddelande
// 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();
Stänga uttag och hantera undantag
Ovanstående exempel lämnade några saker för att göra dem lättare att läsa.
Precis som filer och andra externa resurser är det viktigt att vi berättar operativsystemet när vi är klara med dem. När du är klar med ett uttag, ring
socket.close()
för att stänga det ordentligt.Socklarna hanterar I / O-operationer (Input / Output) som beror på olika externa faktorer. Till exempel vad om den andra sidan plötsligt kopplar ur? Vad händer om det finns nätverksfel? Dessa saker är utanför vår kontroll. Det är därför många socketoperationer kan kasta undantag, särskilt
IOException
.
En mer komplett kod för klienten skulle därför vara något liknande:
// "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
}
Grundläggande server och klient - kompletta exempel
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();
}
}
}
Klient:
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();
}
}
}
Laddar TrustStore och KeyStore från 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();
}
}
}
Att initiera en KeyStore fungerar på samma sätt, förutom att du ersätter alla ord Trust
i ett objektnamn med Key
. Dessutom KeyManager[]
överföras till det första argumentet i SSLContext.init
. Det är SSLContext.init(keyMangers, trustMangers, null)
Exempel på uttag - läsa en webbsida med ett enkelt uttag
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);
}
}
}
Du bör få ett svar som börjar med HTTP/1.1 200 OK
, vilket indikerar ett normalt HTTP-svar, följt av resten av HTTP-rubriken, följt av den råa webbsidan i HTML-form.
Observera att readFully()
är viktig för att förhindra ett för tidigt EOF-undantag. Den sista raden på webbsidan kanske saknas en retur, för att signalera slutet på raden, sedan kommer readLine()
att klaga, så man måste läsa den för hand eller använda verktygsmetoder från Apache commons-io IOUtils
Detta exempel är tänkt som en enkel demonstration av att ansluta till en befintlig resurs med hjälp av ett uttag, det är inte ett praktiskt sätt att komma åt webbsidor. Om du behöver komma åt en webbsida med Java är det bäst att använda ett befintligt HTTP-klientbibliotek som Apaches HTTP-klient eller Googles HTTP-klient
Grundläggande klient / serverkommunikation med 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);
}
}
I det här fallet args[0]
vi in serverns adress via ett argument ( args[0]
). Hamnen vi använder är 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);
}
}
På serversidan, förklara ett DatagramSocket på samma port som vi skickade vårt meddelande till (4160) och vänta på ett svar.
Multicasting
Multicasting är en typ av Datagram Socket. Till skillnad från vanliga Datagram, hanterar inte Multicasting varje klient individuellt utan istället skickar den till en IP-adress och alla abonnerade klienter får meddelandet.
Exempelkod för serversidan:
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();
}
}
Exempelkod för en klientsida:
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();
}
}
Kod för att köra servern:
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();
}
}
Kod för att köra en klient:
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();
}
}
Kör klienten först: Klienten måste prenumerera på IP-adressen innan den kan börja ta emot några paket. Om du startar servern och ringer metoden send()
och sedan skapar en klient (& ring printMessage()
). Ingenting kommer att hända eftersom klienten anslöt efter att meddelandet skickades.
Inaktivera tillfälligt SSL-verifiering (för teständamål)
Ibland i en utvecklings- eller testmiljö kanske SSL-certifikatkedjan inte har varit fullt etablerad (ännu).
För att fortsätta utveckla och testa kan du stänga av SSL-verifiering programmatiskt genom att installera en "all-trusting" trust manager:
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();
}
Nedladdning av en fil med kanal
Om filen redan finns skrivs den över!
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 */ }
anteckningar
- Lämna inte fångstblocken tomma!
- Vid fel, kontrollera om fjärrfilen finns
- Detta är en blockerande operation, kan ta lång tid med stora filer