ホームページ >Java >&#&チュートリアル >Java がネイティブ ソケット通信メカニズムを実装する方法の原理の詳細な説明
この記事では、JAVA でのネイティブ ソケット通信メカニズムの実装原理を主に紹介します。編集者が非常に優れていると考えたので、参考として共有します。編集者をフォローして見てみましょう。この記事では、JAVA のネイティブ ソケット通信メカニズムの原理を紹介し、それを皆さんと共有します。詳細は次のとおりです:
jdk == 1.8
。知識ポイント
ソケット接続処理
ソケット接続を確立します
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);
ソケットの入出力ストリームを処理します
ソケット接続は実際にはファイル ストリームの処理に似ており、どちらも IO 操作を実行します。
入力ストリームと出力ストリームを取得するコードは次のとおりです:
// 输入流 InputStream in = socket.getInputStream(); // 输出流 OutputStream out = socket.getOutputStream();IOストリームの処理に関しては、通常、IOストリームを直接処理する場合は、対応するパッケージ化クラスを使用します。 []、これは比較的面倒です。ラッパークラスを使用すると、string や int などの型で直接処理できるため、IO バイト操作が簡素化されます。 以下では、処理のための入力および出力パッケージング クラスとして
を使用します。
// 获取 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)); }
BufferedReader
与 PrintWriter
データのリクエストとレスポンス
IO パッケージング クラスのサポートにより、文字列形式で直接送信でき、パッケージング クラスはデータを対応するバイト ストリームに変換するのに役立ちます。
HTTP 経由で Baidu サイトにアクセスしているため、追加の出力形式を定義する必要はありません。標準の HTTP 伝送形式を使用して、要求応答を実行できます (一部の特定の RPC フレームワークでは通信形式がカスタマイズされている場合があります)。
リクエストされたデータコンテンツは次のように処理されます:
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"; } }リクエストデータを送信するコードは次のとおりです:
// 发起请求 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); }この時点で、接続の作成と送信のためのコアコードがすべて完了しました。ネイティブソケットでのリクエストとレスポンスの受信。 完全なコードは次のとおりです:
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)); } }以下に、クライアントをインスタンス化してソケット通信を行った結果を示します。
public class Application { public static void main(String[] args) { new SocketHttpClient().start("www.baidu.com", 80); } }結果出力:
モデル最適化要求
このように、関数の実装には問題ありませんが。しかし、詳しく見てみると、IO の書き込みおよび読み取りプロセス中に IO ブロッキングが発生していることがわかります。つまり:// 会发生 IO 阻塞 writer.write(HttpUtil.compositeRequest(host)); reader.readLine();したがって、10 の異なるサイトを同時にリクエストしたい場合は、次のようになります:
public class SingleThreadApplication { public static void main(String[] args) { // HttpConstant.HOSTS 为 站点集合 for (String host: HttpConstant.HOSTS) { new SocketHttpClient().start(host, HttpConstant.PORT); } } }最初のリクエストの応答が完了した後、次のサイトの処理が開始される必要があります。 これはサーバー側でより明らかですが、ここでのコードはクライアント接続ですが、具体的な操作はサーバー側のものと似ています。リクエストは 1 つずつ順番に処理することしかできず、これでは応答時間の基準を確実に満たせません。
マルチスレッド
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(); } } }この方法は、最初は便利に見えますが、大量の同時実行により、アプリケーションは大量のスレッドを使用することになります。ご存知のとおり、サーバー上では、各スレッドが実際にファイル ハンドルを占有します。サーバー上のハンドルの数は限られており、スレッドの数が多いと、スレッド間の切り替えにかなりの消費が発生します。したがって、この方法は、同時実行数が多いシナリオでは耐えられないはずです。
マルチスレッド+スレッドプール処理
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); } } }起動スレッド数は、一般的にCPU集中型はN+1(NはCPUコア数)、IO集中型は2N+1となります。
この方法が最適だと思われます。スレッドが複数のソケット接続を同時に処理でき、各ソケットの入出力データの準備ができていないときにブロックされない場合、より良いものはありますか?この技術を「IO多重化」と呼びます。対応する実装は、JAVA の nio パッケージで提供されます。
以上がJava がネイティブ ソケット通信メカニズムを実装する方法の原理の詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。