ホームページ  >  記事  >  Java  >  Javaレビューに基づくネットワーク通信のアプリケーション分析

Javaレビューに基づくネットワーク通信のアプリケーション分析

黄舟
黄舟オリジナル
2016-12-19 14:55:221150ブラウズ

TCP接続

TCPの基本はSocketです。 TCP接続では、クライアントとサーバーが接続を確立した後は、基本的にI/Oの制御を行います。

まず、クライアントとサーバーに分けられる単純な TCP 通信を見てみましょう。

クライアントのコードは次のとおりです:

简单的TCP客户端 
 import java.net.*;
 import java.io.*;
 public class SimpleTcpClient {

     public static void main(String[] args) throws IOException
     {
         Socket socket = null;
         BufferedReader br = null;
         PrintWriter pw = null;
         BufferedReader brTemp = null;
         try
         {
             socket = new Socket(InetAddress.getLocalHost(), 5678);
             br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
             pw = new PrintWriter(socket.getOutputStream());
             brTemp = new BufferedReader(new InputStreamReader(System.in));
             while(true)
             {
                 String line = brTemp.readLine();
                 pw.println(line);
                 pw.flush();
                 if (line.equals("end")) break;
                 System.out.println(br.readLine());
             }
         }
         catch(Exception ex)
         {
             System.err.println(ex.getMessage());
         }
         finally
         {
             if (socket != null) socket.close();
             if (br != null) br.close();
             if (brTemp != null) brTemp.close();
             if (pw != null) pw.close();
         }
     }
 }

サーバーのコードは次のとおりです:

简单版本TCP服务器端
 import java.net.*;
 import java.io.*;
 public class SimpleTcpServer {

     public static void main(String[] args) throws IOException
     {
         ServerSocket server = null;
         Socket client = null;
         BufferedReader br = null;
         PrintWriter pw = null;
         try
         {
             server = new ServerSocket(5678);
             client = server.accept();
             br = new BufferedReader(new InputStreamReader(client.getInputStream()));
             pw = new PrintWriter(client.getOutputStream());
             while(true)
             {
                 String line = br.readLine();
                 pw.println("Response:" + line);
                 pw.flush();
                 if (line.equals("end")) break;
             }
         }
         catch(Exception ex)
         {
             System.err.println(ex.getMessage());
         }
         finally
         {
             if (server != null) server.close();
             if (client != null) client.close();
             if (br != null) br.close();
             if (pw != null) pw.close();
         }
     }
 }

ここでのサーバーの機能は非常に単純で、クライアントから送信されたメッセージを受信し、メッセージを「そのまま」返します。クライアント。クライアントが「end」を送信すると通信は終了します。


上記のコードは基本的に、TCP 通信プロセス中のクライアントとサーバーの主要なフレームワークの概要を示しています。上記のコードでは、サーバーは常にクライアントからのリクエストを 1 つだけ処理できることがわかります。これは、クライアントのリクエストが受信されたときに、サーバーにマルチスレッドを追加して、対応するリクエストを処理する方法とは異なります。

改善されたサーバー側のコードは次のとおりです:

多线程版本的TCP服务器端
 import java.net.*;
 import java.io.*;
 public class SmartTcpServer {
     public static void main(String[] args) throws IOException
     {
         ServerSocket server = new ServerSocket(5678);
         while(true)
         {
             Socket client = server.accept();
             Thread thread = new ServerThread(client);
             thread.start();
         }
     }
 }

 class ServerThread extends Thread
 {
     private Socket socket = null;

     public ServerThread(Socket socket)
     {
         this.socket = socket;
     }

     public void run() {
         BufferedReader br = null;
         PrintWriter pw = null;
         try
         {
             br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
             pw = new PrintWriter(socket.getOutputStream());
             while(true)
             {
                 String line = br.readLine();
                 pw.println("Response:" + line);
                 pw.flush();
                 if (line.equals("end")) break;
             }
         }
         catch(Exception ex)
         {
             System.err.println(ex.getMessage());
         }
         finally
         {
             if (socket != null)
                 try {
                     socket.close();
                 } catch (IOException e1) {
                     e1.printStackTrace();
                 }
             if (br != null)
                 try {
                     br.close();
                 } catch (IOException e) {
                     e.printStackTrace();
                 }
             if (pw != null) pw.close();
         }
     }
 }

変更されたサーバー側は、クライアントからの複数のリクエストを同時に処理できます。


プログラミングのプロセスでは、通常、パフォーマンスを向上させるためにデータベース接続を直接破棄せずに、「リソース」という概念を使用します。データベース接続プール。複数のデータベース接続を管理するため、再利用の目的は達成されました。ソケット接続の場合、プログラムで多数のソケット接続が必要な場合、各接続を再確立する必要がある場合、これは非常に非効率なアプローチになります。

データベース接続プールと同様に、TCP 接続プールも設計できます。ここでの考え方は、配列を使用して複数のソケット接続を維持し、別のステータス配列を使用してプログラムが各ソケット接続が使用されているかどうかを記述することです。ソケット接続が必要な場合、ステータス配列を走査し、最初の未使用のソケット接続を取り出します。すべての接続が使用中の場合は、例外がスローされます。これは非常に直感的でシンプルな「スケジューリング戦略」であり、多くのオープンソースまたは商用フレームワーク (Apache/Tomcat) には同様の「リソース プール」があります。

TCP 接続プールのコードは次のとおりです。

一个简单的TCP连接池
 import java.net.*;
 import java.io.*;
 public class TcpConnectionPool {

     private InetAddress address = null;
     private int port;
     private Socket[] arrSockets = null;
     private boolean[] arrStatus = null;
     private int count;

     public TcpConnectionPool(InetAddress address, int port, int count)
     {
         this.address = address;
         this.port = port;
         this .count = count;
         arrSockets = new Socket[count];
         arrStatus = new boolean[count];

         init();
     }

     private void init()
     {
         try
         {
             for (int i = 0; i < count; i++)
             {
                 arrSockets[i] = new Socket(address.getHostAddress(), port);
                 arrStatus[i] = false;
             }
         }
         catch(Exception ex)
         {
             System.err.println(ex.getMessage());
         }
     }

     public Socket getConnection()
     {
         if (arrSockets == null) init();
         int i = 0;
         for(i = 0; i < count; i++)
         {
             if (arrStatus[i] == false) 
             {
                 arrStatus[i] = true;
                 break;
             }
         }
         if (i == count) throw new RuntimeException("have no connection availiable for now.");

         return arrSockets[i];
     }

     public void releaseConnection(Socket socket)
     {
         if (arrSockets == null) init();
         for (int i = 0; i < count; i++)
         {
             if (arrSockets[i] == socket)
             {
                 arrStatus[i] = false;
                 break;
             }
         }
     }

     public void reBuild()
     {
         init();
     }

     public void destory()
     {
         if (arrSockets == null) return;

         for(int i = 0; i < count; i++)
         {
             try
             {
                 arrSockets[i].close();
             }
             catch(Exception ex)
             {
                 System.err.println(ex.getMessage());
                 continue;
             }
         }
     }
 }

UDP 接続


UDP は、通常、高いリアルタイム性要件と低い精度要件がある状況で使用されます。オンラインビデオ。 UDP では「パケットロス」が発生します。サーバーが起動していないと、クライアントがメッセージを送信するときに例外が報告されますが、UDP では例外は生成されません。

UDP通信で使用される2つのクラスはDatagramSocketとDatagramPacketで、後者は通信内容を格納します。

以下は、TCP と同様に、クライアントとサーバーの 2 つの部分に分かれています。 クライアント側のコードは次のとおりです。

UDP通信客户端
 import java.net.*;
 import java.io.*;
 public class UdpClient {

     public static void main(String[] args)
     {
         try
         {
             InetAddress host = InetAddress.getLocalHost();
             int port = 5678;
             BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
             while(true)
             {
                 String line = br.readLine();
                 byte[] message = line.getBytes();
                 DatagramPacket packet = new DatagramPacket(message, message.length, host, port);
                 DatagramSocket socket = new DatagramSocket();
                 socket.send(packet);
                 socket.close();
                 if (line.equals("end")) break;
             }
             br.close();
         }
         catch(Exception ex)
         {
             System.err.println(ex.getMessage());
         }
     }
 }

サーバー側のコードは次のとおりです。ここでも TCP と同様に、クライアントが「終了」メッセージを送信すると通信が終了したものとみなしますが、実際にはそのような設計は不要であり、クライアントはいつでも切断する必要はありません。サーバーのステータスに注意してください。

マルチキャスト


マルチキャストは、UDP と同様の方法を使用し、クラス D IP アドレスと標準の UDP ポート番号を使用します (224.0.0.0 を除く)。

マルチキャストで使用されるクラスは MulticastSocket で、これには、joinGroup と LeaveGroup という 2 つの注目すべきメソッドがあります。

以下はマルチキャストの例です: クライアントコードは次のとおりです:

UDP通信服务器端
 import java.net.*;
 import java.io.*;
 public class UdpServer {

     public static void main(String[] args)
     {
         try
         {
             int port = 5678;
             DatagramSocket dsSocket = new DatagramSocket(port);
             byte[] buffer = new byte[1024];
             DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
             while(true)
             {
                 dsSocket.receive(packet);
                 String message = new String(buffer, 0, packet.getLength());
                 System.out.println(packet.getAddress().getHostName() + ":" + message);
                 if (message.equals("end")) break;
                 packet.setLength(buffer.length);
             }
             dsSocket.close();
         }
         catch(Exception ex)
         {
             System.err.println(ex.getMessage());
         }
     }
 }

サーバーコードは次のとおりです:

多播通信客户端
 import java.net.*;
 import java.io.*;
 public class MulticastClient {

     public static void main(String[] args)
     {
         BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
         try
         {
             InetAddress address = InetAddress.getByName("230.0.0.1");
             int port = 5678;
             while(true)
             {
                 String line = br.readLine();
                 byte[] message = line.getBytes();
                 DatagramPacket packet = new DatagramPacket(message, message.length, address, port);
                 MulticastSocket multicastSocket = new MulticastSocket();
                 multicastSocket.send(packet);
                 if (line.equals("end")) break;
             }
             br.close();
         }
         catch(Exception ex)
         {
             System.err.println(ex.getMessage());
         }
     }
 }

NIO (新しいIO)

NIOは、によって導入された新しいIO APIのセットです。 JDK1.4 では、バッファ管理、ネットワーク通信、ファイル アクセス、および文字セット操作が新しい設計になっています。ネットワーク通信の場合、NIO はバッファーとチャネルの概念を使用します。

以下は NIO の例ですが、上で述べたコーディング スタイルとは大きく異なります。

多播通信服务器端
 import java.net.*;
 import java.io.*;
 public class MulticastServer {

     public static void main(String[] args)
     {
         int port = 5678;
         try
         {
             MulticastSocket multicastSocket = new MulticastSocket(port);
             InetAddress address = InetAddress.getByName("230.0.0.1");
             multicastSocket.joinGroup(address);
             byte[] buffer = new byte[1024];
             DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
             while(true)
             {
                 multicastSocket.receive(packet);
                 String message = new String(buffer, packet.getLength());
                 System.out.println(packet.getAddress().getHostName() + ":" + message);
                 if (message.equals("end")) break;
                 packet.setLength(buffer.length);
             }
             multicastSocket.close();
         }
         catch(Exception ex)
         {
             System.err.println(ex.getMessage());
         }
     }
 }

上記のコードは、ローカル URL にアクセスして、その内容を出力しようとします。

上記は Java レビューに基づいたネットワーク通信のアプリケーション分析です。その他の関連コンテンツについては、PHP 中国語 Web サイト (www.php.cn) に注目してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。