Maison Java javaDidacticiel Explication détaillée des principes selon lesquels Java implémente le mécanisme de communication par socket natif

Explication détaillée des principes selon lesquels Java implémente le mécanisme de communication par socket natif

Aug 20, 2017 am 09:10 AM
java socket 原生

Cet article présente principalement le principe d'implémentation du mécanisme de communication par socket natif en JAVA. L'éditeur pense que c'est plutôt bien, je vais donc le partager avec vous maintenant et le donner comme référence. Suivons l'éditeur et jetons un coup d'œil.

Cet article présente le principe du mécanisme de communication de socket natif en JAVA et le partage avec tout le monde. Les détails sont les suivants :

Environnement actuel.

jdk == 1.8

Points de connaissance

  • Traitement des connexions de socket

  • Traitement des flux d'entrée et de sortie IO

  • Traitement du format de données de demande

  • Optimisation du modèle de demande

Scénario

Aujourd'hui, parlons des problèmes de communication des sockets en JAVA. Nous prenons ici comme exemple le modèle le plus simple, une demande, une réponse, en supposant que nous devons maintenant communiquer avec le site Baidu. Comment pouvons-nous utiliser le socket natif de JAVA pour y parvenir ?

Établir une connexion socket

Tout d'abord, nous devons établir une connexion socket (code principal)


import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
    
// 初始化 socket
Socket socket = new Socket();
// 初始化远程连接地址
SocketAddress remote = new InetSocketAddress(host, port);
// 建立连接
socket.connect(remote);
Copier après la connexion

Traitement des flux d'entrée et de sortie de socket

Après avoir réussi à établir une connexion de socket, nous pouvons obtenir ses flux d'entrée et de sortie. L'essence de la communication est le traitement. des flux d’entrée et de sortie. Grâce au flux d'entrée, les données de la connexion réseau sont lues et via le flux de sortie, les données locales sont envoyées à l'extrémité distante.

La connexion socket est en fait quelque peu similaire au traitement des flux de fichiers, les deux effectuent des opérations d'E/S.

Le code d'obtention des flux d'entrée et de sortie est le suivant :


// 输入流
InputStream in = socket.getInputStream();
// 输出流
OutputStream out = socket.getOutputStream();
Copier après la connexion

Concernant le traitement des flux IO, nous utilisons généralement les classes de packaging correspondantes pour traiter les flux IO, s'ils sont traités directement, nous devons opérer sur byte[], ce qui est relativement fastidieux. Si nous utilisons une classe wrapper, nous pouvons la traiter directement avec des types tels que string et int, ce qui simplifie les opérations sur les octets IO.

est traité ci-dessous en utilisant BufferedReader et PrintWriter comme classes d'empaquetage d'entrée et de sortie.


// 获取 socket 输入流
private BufferedReader getReader(Socket socket) throws IOException {
  InputStream in = socket.getInputStream();
  return new BufferedReader(new InputStreamReader(in));
}

// 获取 socket 输出流
private PrintWriter getWriter(Socket socket) throws IOException {
  OutputStream out = socket.getOutputStream();
  return new PrintWriter(new OutputStreamWriter(out));
}
Copier après la connexion

Demande et réponse de données

Avec la connexion par socket et le flux d'entrée et de sortie IO, les éléments suivants devraient être fait Envoyer les données de la demande à et obtenir les résultats de la réponse à la demande.

Avec la prise en charge de la classe d'empaquetage IO, nous pouvons transmettre directement au format chaîne, et la classe d'empaquetage nous aidera à convertir les données en flux d'octets correspondant.

Étant donné que nous accédons au site baidu via HTTP, nous n'avons pas besoin de définir de formats de sortie supplémentaires. En utilisant le format de transmission HTTP standard, vous pouvez effectuer des réponses aux requêtes (certains frameworks RPC spécifiques peuvent avoir des formats de communication personnalisés).

Le contenu des données demandées est traité comme suit :


public class HttpUtil {

  public static String compositeRequest(String host){

    return "GET / HTTP/1.1\r\n" +
        "Host: " + host + "\r\n" +
        "User-Agent: curl/7.43.0\r\n" +
        "Accept: */*\r\n\r\n";
  }
  
}
Copier après la connexion

Le code d'envoi des données de la demande est le suivant :


// 发起请求
PrintWriter writer = getWriter(socket);
writer.write(HttpUtil.compositeRequest(host));
writer.flush();
接收响应数据代码如下:

// 读取响应
String msg;
BufferedReader reader = getReader(socket);
while ((msg = reader.readLine()) != null){
  System.out.println(msg);
}
Copier après la connexion

Jusqu'à présent, nous avons fini de parler de tous les codes de base pour créer des connexions, envoyer des requêtes et recevoir des réponses sous des sockets natifs.

Le code complet est le suivant :


import java.io.*;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import com.test.network.util.HttpUtil;

public class SocketHttpClient {

  public void start(String host, int port) {

    // 初始化 socket
    Socket socket = new Socket();

    try {
      // 设置 socket 连接
      SocketAddress remote = new InetSocketAddress(host, port);
      socket.setSoTimeout(5000);
      socket.connect(remote);

      // 发起请求
      PrintWriter writer = getWriter(socket);
      System.out.println(HttpUtil.compositeRequest(host));
      writer.write(HttpUtil.compositeRequest(host));
      writer.flush();

      // 读取响应
      String msg;
      BufferedReader reader = getReader(socket);
      while ((msg = reader.readLine()) != null){
        System.out.println(msg);
      }

    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      try {
        socket.close();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }

  }

  private BufferedReader getReader(Socket socket) throws IOException {
    InputStream in = socket.getInputStream();
    return new BufferedReader(new InputStreamReader(in));
  }

  private PrintWriter getWriter(Socket socket) throws IOException {
    OutputStream out = socket.getOutputStream();
    return new PrintWriter(new OutputStreamWriter(out));
  }

}
Copier après la connexion

Ci-dessous, nous montrons les résultats de la communication socket en instanciant un client.


public class Application {

  public static void main(String[] args) {

    new SocketHttpClient().start("www.baidu.com", 80);

  }
}
Copier après la connexion

Sortie du résultat :

Optimisation du modèle de demande

De cette façon, même s'il n'y a aucun problème pour réaliser la fonction. Mais lorsque nous y regardons de plus près, nous constatons que le blocage des E/S se produit pendant le processus d'écriture et de lecture des E/S. Soit :


// 会发生 IO 阻塞
writer.write(HttpUtil.compositeRequest(host));
reader.readLine();
Copier après la connexion

Donc si vous souhaitez demander 10 sites différents en même temps, comme suit :


public class SingleThreadApplication {

  public static void main(String[] args) {

    // HttpConstant.HOSTS 为 站点集合
    for (String host: HttpConstant.HOSTS) {

      new SocketHttpClient().start(host, HttpConstant.PORT);

    }

  }
}
Copier après la connexion

Il doit compléter la première réponse à la demande avant de lancer le traitement suivant du site.

Cela est plus évident côté serveur. Bien que le code ici soit une connexion client, les opérations spécifiques sont similaires à celles côté serveur. Les demandes ne peuvent être traitées qu'en série une par une, ce qui ne respectera certainement pas la norme de temps de réponse.

  • Multi-threading

Certaines personnes pensent que ce n'est pas du tout un problème, JAVA est un langage de programmation multi-thread. Dans cette situation, un modèle multithread est le plus approprié.


public class MultiThreadApplication {

  public static void main(String[] args) {

    for (final String host: HttpConstant.HOSTS) {

      Thread t = new Thread(new Runnable() {
        public void run() {
          new SocketHttpClient().start(host, HttpConstant.PORT);
        }
      });

      t.start();

    }
  }
}
Copier après la connexion

Cette méthode semble utile au début, mais lorsque la quantité de concurrence est importante, l'application utilisera beaucoup de threads. Comme nous le savons tous, sur le serveur, chaque thread occupe en fait un descripteur de fichier. Le nombre de handles sur le serveur est limité et un grand nombre de threads entraînera une consommation considérable de commutation entre les threads. Par conséquent, cette méthode doit être insupportable dans les scénarios à forte concurrence.

  • Traitement multi-thread + pool de threads

Comme trop de threads ne suffisent pas, nous pouvons simplement contrôler le nombre de threads créés. Seul un nombre fixe de threads est démarré pour le traitement des sockets, qui utilise non seulement le traitement multithread, mais contrôle également la consommation des ressources du système.


public class ThreadPoolApplication {

  public static void main(String[] args) {

    ExecutorService executorService = Executors.newFixedThreadPool(8);

    for (final String host: HttpConstant.HOSTS) {

      Thread t = new Thread(new Runnable() {
        public void run() {
          new SocketHttpClient().start(host, HttpConstant.PORT);
        }
      });

      executorService.submit(t);
      new SocketHttpClient().start(host, HttpConstant.PORT);

    }

  }
}
Copier après la connexion

Concernant le nombre de threads démarrés, généralement le type gourmand en CPU sera fixé à N+1 (N est le nombre de cœurs CPU), et le Le type intensif en IO sera défini sur 2N + 1 .

Cette méthode semble être la meilleure. Y a-t-il quelque chose de mieux ? Si un thread peut gérer plusieurs connexions de socket en même temps et ne se bloque pas lorsque les données d’entrée et de sortie de chaque socket ne sont pas prêtes, est-ce mieux ? Cette technologie est appelée « multiplexage IO ». L'implémentation correspondante est fournie dans le package nio de JAVA.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

AI Hentai Generator

AI Hentai Generator

Générez AI Hentai gratuitement.

Article chaud

R.E.P.O. Crystals d'énergie expliqués et ce qu'ils font (cristal jaune)
4 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Meilleurs paramètres graphiques
4 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Comment réparer l'audio si vous n'entendez personne
4 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: Comment déverrouiller tout dans Myrise
1 Il y a quelques mois By 尊渡假赌尊渡假赌尊渡假赌

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Nombre parfait en Java Nombre parfait en Java Aug 30, 2024 pm 04:28 PM

Guide du nombre parfait en Java. Nous discutons ici de la définition, comment vérifier le nombre parfait en Java ?, des exemples d'implémentation de code.

Générateur de nombres aléatoires en Java Générateur de nombres aléatoires en Java Aug 30, 2024 pm 04:27 PM

Guide du générateur de nombres aléatoires en Java. Nous discutons ici des fonctions en Java avec des exemples et de deux générateurs différents avec d'autres exemples.

Weka en Java Weka en Java Aug 30, 2024 pm 04:28 PM

Guide de Weka en Java. Nous discutons ici de l'introduction, de la façon d'utiliser Weka Java, du type de plate-forme et des avantages avec des exemples.

Numéro de Smith en Java Numéro de Smith en Java Aug 30, 2024 pm 04:28 PM

Guide du nombre de Smith en Java. Nous discutons ici de la définition, comment vérifier le numéro Smith en Java ? exemple avec implémentation de code.

Questions d'entretien chez Java Spring Questions d'entretien chez Java Spring Aug 30, 2024 pm 04:29 PM

Dans cet article, nous avons conservé les questions d'entretien Java Spring les plus posées avec leurs réponses détaillées. Pour que vous puissiez réussir l'interview.

Break or Return of Java 8 Stream Forach? Break or Return of Java 8 Stream Forach? Feb 07, 2025 pm 12:09 PM

Java 8 présente l'API Stream, fournissant un moyen puissant et expressif de traiter les collections de données. Cependant, une question courante lors de l'utilisation du flux est: comment se casser ou revenir d'une opération FOREAK? Les boucles traditionnelles permettent une interruption ou un retour précoce, mais la méthode Foreach de Stream ne prend pas directement en charge cette méthode. Cet article expliquera les raisons et explorera des méthodes alternatives pour la mise en œuvre de terminaison prématurée dans les systèmes de traitement de flux. Lire plus approfondie: Améliorations de l'API Java Stream Comprendre le flux Forach La méthode foreach est une opération terminale qui effectue une opération sur chaque élément du flux. Son intention de conception est

Horodatage à ce jour en Java Horodatage à ce jour en Java Aug 30, 2024 pm 04:28 PM

Guide de TimeStamp to Date en Java. Ici, nous discutons également de l'introduction et de la façon de convertir l'horodatage en date en Java avec des exemples.

Programme Java pour trouver le volume de la capsule Programme Java pour trouver le volume de la capsule Feb 07, 2025 am 11:37 AM

Les capsules sont des figures géométriques tridimensionnelles, composées d'un cylindre et d'un hémisphère aux deux extrémités. Le volume de la capsule peut être calculé en ajoutant le volume du cylindre et le volume de l'hémisphère aux deux extrémités. Ce tutoriel discutera de la façon de calculer le volume d'une capsule donnée en Java en utilisant différentes méthodes. Formule de volume de capsule La formule du volume de la capsule est la suivante: Volume de capsule = volume cylindrique volume de deux hémisphères volume dans, R: Le rayon de l'hémisphère. H: La hauteur du cylindre (à l'exclusion de l'hémisphère). Exemple 1 entrer Rayon = 5 unités Hauteur = 10 unités Sortir Volume = 1570,8 unités cubes expliquer Calculer le volume à l'aide de la formule: Volume = π × r2 × h (4

See all articles