Поиск…


Синтаксис

  • новый Socket («localhost», 1234); // Подключается к серверу по адресу «localhost» и порту 1234
  • новый SocketServer («localhost», 1234); // Создает сервер сокетов, который может прослушивать новые сокеты по адресу localhost и порту 1234
  • socketServer.accept (); // Принимает новый объект Socket, который может использоваться для связи с клиентом

Основные клиентские и серверные коммуникации с использованием разъема

Сервер: запуск и ожидание входящих соединений

//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.
}

Сервер: обработка клиентов

Мы будем обрабатывать каждый клиент в отдельном потоке, чтобы сразу несколько клиентов могли взаимодействовать с сервером. Этот метод работает отлично, пока количество клиентов невелико (<< 1000 клиентов, в зависимости от архитектуры ОС и ожидаемой загрузки каждого потока).

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();

Клиент: подключитесь к серверу и отправьте сообщение

// 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();

Закрытие разъемов и исключение обработки

В приведенных выше примерах были некоторые вещи, которые упрощали их чтение.

  1. Так же, как файлы и другие внешние ресурсы, важно сообщить ОС, когда мы с ними закончим. Когда мы закончим сокет, вызовите socket.close() чтобы правильно закрыть его.

  2. Сокеты обрабатывают операции ввода / вывода (ввода / вывода), которые зависят от множества внешних факторов. Например, что, если другая сторона внезапно отключится? Что делать, если есть сетевая ошибка? Эти вещи находятся вне нашего контроля. Вот почему многие операции сокета могут вызывать исключения, особенно IOException .

Таким образом, более полный код для клиента будет примерно таким:

 // "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
 }

Базовый сервер и клиент - полные примеры

Сервер:

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();
        }

    }
}

Клиент:

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 и KeyStore из 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();
            }
        
    }
}

Intiating KeyStore работает одинаково, за исключением замены любого слова Trust в имени объекта с помощью Key . Кроме того, массив KeyManager[] должен быть передан первому аргументу SSLContext.init . Это SSLContext.init(keyMangers, trustMangers, null)

Пример сокета - чтение веб-страницы с использованием простого сокета

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);
        }
    }
}

Вы должны получить ответ, который начинается с HTTP/1.1 200 OK , что указывает на обычный HTTP-ответ, за которым следует остальная часть HTTP-заголовка, а затем необработанная веб-страница в форме HTML.

Обратите внимание, что readFully() важен для предотвращения преждевременного исключения EOF. В последней строке веб-страницы может отсутствовать возврат, чтобы сигнализировать о конце строки, а затем readLine() будет жаловаться, поэтому нужно прочитать ее вручную или использовать служебные методы из Apache commons-io IOUtils

Этот пример предназначен для простой демонстрации подключения к существующему ресурсу с помощью сокета, это не практический способ доступа к веб-страницам. Если вам нужно получить доступ к веб-странице с помощью Java, лучше использовать существующую клиентскую библиотеку HTTP, такую ​​как HTTP-клиент Apache или HTTP-клиент Google

Основная клиентская / серверная связь с использованием UDP (датаграмма)

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);
    }
}

В этом случае мы передаем адрес сервера через аргумент ( args[0] ). Порт, который мы используем, - 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);
    }
}

На стороне сервера объявите DatagramSocket в том же порту, на который мы отправили наше сообщение (4160), и дождитесь ответа.

Multicasting

Многоадресная рассылка - это тип Datagram Socket. В отличие от обычных дейтаграмм, многоадресная рассылка не обрабатывает каждый клиент отдельно, а отправляет его на один IP-адрес, и все подписанные клиенты получат сообщение.

введите описание изображения здесь

Пример кода для серверной части:

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();
    }
}

Пример кода для клиентской стороны:

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();
    }
}

Код для запуска сервера:

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();
    }
}

Код для запуска клиента:

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();
    }
}

Сначала запустите клиент: клиент должен подписаться на IP-адрес, прежде чем он сможет начать получать какие-либо пакеты. Если вы запустите сервер и вызовите метод send() , а затем создайте клиент (& call printMessage() ). Ничего не произойдет, потому что клиент подключился после отправки сообщения.

Временное отключение проверки SSL (для целей тестирования)

Иногда в среде разработки или тестирования цепочка сертификатов SSL, возможно, не была полностью установлена ​​(пока).

Чтобы продолжить разработку и тестирование, вы можете отключить проверку SSL программно, установив «доверительный» доверительный менеджер:

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();
}

Загрузка файла с использованием канала

Если файл уже существует, он будет перезаписан!

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 */ }

Заметки

  • Не оставляйте блоки захвата пустыми!
  • В случае ошибки проверьте, существует ли удаленный файл
  • Это операция блокировки, может занять много времени с большими файлами


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow