Java Socketの仕組みを詳しく理解する

10100 ワード

Socketのいきさつ
以下の分析は主にコンピュータネットワーク(謝希仁第7版)を参照してまとめられたもので、システム呼び出し---アプリケーションプログラミングインターフェースAPI--->ソケットインターフェースからSocketの経緯を分析し、もちろんウィキペディアにもSocketの詳細な説明がある.
1.システムコール
ほとんどのオペレーティングシステムでは、システム呼び出しメカニズムを使用して、アプリケーションとオペレーティングシステムの間で制御権を伝達します.プログラマにとって、システム呼び出しは一般的なプログラム設計における関数呼び出しと非常に似ています.
2.アプリケーションプログラミングインターフェースAPI
アプリケーション・プロセスがシステム・コールを開始すると、制御権はアプリケーション・プロセスからシステム・コール・インタフェースに渡され、このインタフェースはコンピュータのオペレーティング・システムに制御権を渡します.オペレーティングシステムは、この呼び出しを内部プロシージャに転送し、要求された操作を実行します.内部プロシージャが実行されると、制御権はシステム呼び出しインタフェースを介してアプリケーションプロセスに返されます.
システム呼び出しインタフェースは、実際にはアプリケーションプロセスの制御権とオペレーティングシステムの制御権を変換するインタフェースであり、アプリケーションプログラミングインタフェースAPIである.
3.ソケット
TCP/IPプロトコルファミリーは、複数のオペレーティングシステムの環境下で動作可能に設計されているため、TCP/IP規格は、システム設計者がAPIに関する具体的な実装の詳細を選択することを可能にする.
現在、TCP/IPを用いたアプリケーションプログラミングインターフェースAPIをプログラムで提供できる最も有名なのはソケットインターフェースである.
ソケットは物理的エンティティではなく抽象的であり、ソケットはアプリケーションの作成と使用を提供するデータ構造である.
4.ソケット記述子
アプリケーション・プロセス(クライアントまたはサーバ)がネットワークを使用して通信する必要がある場合は、まずsocketシステム・コールを発行し、オペレーティング・システムにソケットの作成を要求する必要があります.この呼び出しの実際の効果は、オペレーティングシステムにネットワーク通信に必要なシステムリソース(メモリ空間、CPU時間、ネットワーク帯域幅など)をアプリケーションプロセスに割り当てるように要求することである.
オペレーティングシステムは、これらのリソースの合計をソケット記述子(socket descriptor)という番号(小さな整数)で表し、このソケット記述子をアプリケーションプロセスに返します.
Socket通信図
図から分かるように、Socket通信とTCP/IPプロトコルは切り離せない.ホストAとホストBが通信できるようにするには、Socket接続を確立しなければならない.Socket接続を確立するには、下位TCP/IPプロトコルを通じてTCP接続を確立しなければならない.
Socket通信プロトコル分析
前述したように、Socket通信はTCP/IPプロトコルと密接に関連しており、Socketプログラミング通信については、一般的なTCPプロトコルとUDPプロトコルの2つのプロトコルを選択することができます.
UDPプロトコル
UDPプロトコルは、データ・レポート・プロトコルとも呼ばれる接続されていないプロトコルです.データ・レポートを送信するたびに、自機のsocket記述子(上述したソケット記述子)と受信側のsocket記述子を同時に送信する必要がある.そのため、通信のたびに追加のデータが送信されます.
TCPプロトコル
TCPプロトコルは接続されたプロトコルであり、アプリケーションを使用する前にTCP接続を確立する必要があります.だから、通信を行う前に、まずSocket接続を確立する必要があります.1つのsocketはサービス側の傍受要求として、1つのsocketはクライアントとして接続要求を行います.双方が接続を確立してからこそ、双方が通信することができる.
2つのプロトコルの違いと選択
両者の違いを簡単に分析する:
  • UDPでは、データレポートを送信たびに、自機のsocket記述子と受信側のsocket記述子を添付する必要がある.一方、TCPは接続に基づくプロトコルであり、通信のsocket間では通信の前に接続、すなわちTCPの3回の握手を確立する必要があるため、接続の確立には一定の時間がかかる
  • がある.
  • UDPでは、データレポートデータのサイズに64 KBの制限があります.一方、TCPは、TCP通信のsocketペアが接続を確立すると、IOストリームのような通信を行うという制限は存在しない.
  • UDPは信頼できないプロトコルであり、送信されたデータ・レポートは、必ずしもその送信順序に従って受信側のsocketに受信されるとは限らない.TCPは信頼できるプロトコルです.受信側で受信パケットの順序と送信側でのパケットの順序はほぼ一致する(ここではパケットを失う場合は論じない)
  • .
    これといえば、どのプロトコルを選ぶかは、あなたの使用シーンにかかっていますが、TCPプロトコルに基づくSocket通信が多いと思います.もちろん、リアルタイム性の高いサービスもありますが、ローカルエリアネットワークのサービスはUDPのものが多いです.
    TCPプロトコルに基づくJava Socketプログラミングの例
    socketプログラミングは総じて3つのステップに分けられる:接続の確立、データ転送、接続の解放.もちろん、上記の図に示すように、サービス側プログラムとクライアントプログラムの具体的な手順には違いがあります.
    ここではjavaを使います.Netパッケージの下にあるServerSocketクラス(主にサービス側)とSocketクラス(接続の確立用)は、Socket通信インスタンスを実現するために使用されます.
    サービス側作成
    package com.pjmike.Socket;
    
    import java.io.BufferedInputStream;
    import java.io.DataInputStream;
    import java.io.IOException;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.sql.SQLOutput;
    
    /**
     *    
     *
     * @author pjmike
     * @create 2018-08-12 17:43
     */
    public class Server {
        private ServerSocket serverSocket = null;
        private Socket socket = null;
        private DataInputStream input = null;
    
        public Server(int port) {
            try {
                //    
                System.out.println("bind port ...");
                serverSocket = new ServerSocket(port);
                System.out.println("Server started and waiting a client ..");
                //  accept()  ,      
                socket = serverSocket.accept();
                //         
                input = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
                String line = "";
                while (!line.equals("exit")) {
                    try {
                        //readUTF()      writeUTF()      
                        line = input.readUTF();
                        System.out.println("recd: " + line);
                    } catch (IOException o) {
                        o.printStackTrace();
                    }
                }
                //    
                System.out.println("connection closed ...");
                input.close();
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        public static void main(String[] args) {
            Server server = new Server(5000);
        }
    }
    
    

    クライアントプログラム
    package com.pjmike.Socket;
    
    import java.io.*;
    import java.net.Socket;
    import java.nio.Buffer;
    
    /**
     *    
     *
     * @author pjmike
     * @create 2018-08-12 17:52
     */
    public class Client {
        private Socket socket = null;
        private DataOutputStream output = null;
        private BufferedReader input = null;
    
        public Client(String address, int port) {
            try {
                //    
                socket = new Socket(address, port);
                System.out.println("Connected ...");
                //        
                input = new BufferedReader(new InputStreamReader(System.in));
                output = new DataOutputStream(socket.getOutputStream());
    
            } catch (IOException e) {
                e.printStackTrace();
            }
            String line = "";
            while (!line.equals("exit")) {
                try {
                    line = input.readLine();
                    System.out.println("       : "+line);
                    output.writeUTF(line);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            try {
                input.close();
                socket.close();
                output.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        public static void main(String[] args) {
            Client client = new Client("localhost", 5000);
        }
    }
    
    

    テスト
    クライアント
    Connected ...
    hello world
           : hello world
    nihao
           : nihao
    exit
           : exit
    

    サービス側
    bind port ...
    Server started and waiting a client ..
    recd: hello world
    recd: nihao
    recd: exit
    connection closed ...
    
    

    もちろん、複数のクライアントを同じサービス側に接続する必要がある場合もあります.これは難しくありません.マルチスレッド方式を採用し、サーバにaccept()メソッドをループ呼び出し、1つのクライアント要求を受け取るたびに1つのスレッドを開いて処理します.
    小結
    実際、Socketはプロセス間の通信メカニズムであり、Java Socketプログラミングにおいても、通信リンクの確立、データ伝送、リンクの閉鎖の3つのステップに分かれています.ネットワークプログラミングもJava I/O操作と密接に結びついており、I/O操作を熟知していることも少なくない.
    参考資料
  • Java I/Oの動作メカニズムを深く分析する
  • JavaのSocketプログラミング
  • を読み取る
  • Java tutorial: Sockets programming
  • コンピュータネットワーク(謝希仁第7版)