技術共有

Java の高度な重要な知識ポイント - 23 - ネットワーク プログラミング

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

ネットワークプログラミング入門

ソフトウェア構造

  • C/S 構造: 正式名称は Client/Server 構造で、クライアントとサーバーの構造を指します。
  • B/S 構造: 正式名称は Browser/Server Structure で、ブラウザとサーバーの構造を指します。

ネットワーク通信プロトコル

网络通信协议:通信协议是对计算机必须遵守的规则,只有遵守这些规则,计算机之间才能进行通信。

  • TCP/IPプロトコル:伝送制御プロトコル/インターネットプロトコル(Transmission Control Protocol/Internet Protocol)は、
    インターネットの最も基本的で広く普及しているプロトコル。
    ここに画像の説明を挿入します

プロトコルの分類

java.net 包中提供了两种常见的网络协议的支持

  1. TCP: 伝送制御プロトコル。 TCP プロトコルはコネクション指向の通信プロトコルです。つまり、データを送信する前に、送信側と受信側の間で論理接続が確立され、その後、両者間で信頼性が高くエラーのないデータ送信が行われます。コンピューター。
  2. UDP: ユーザー データグラム プロトコル。 UDP プロトコルはコネクションレス型プロトコルです。データ送信時には、相手のサービスが開始されているかどうかに関係なく、データ、データ送信元、送信先をデータパケットに直接カプセル化して送信します。各パケットのサイズは 64k に制限されています。接続がないため、通信速度は速いですが、データが失われやすいため、信頼性の低いプロトコルです。

TCP の 3 ウェイ ハンドシェイク: TCP プロトコルでは、データ送信の準備段階で、接続の信頼性を確保するためにクライアントとサーバーの間で 3 つの対話が行われます。

  • 最初のハンドシェイクでは、クライアントはサーバーに接続リクエストを送信し、サーバーによる確認を待ちます。
  • 2 回目のハンドシェイクでは、サーバーはクライアントに応答を返し、接続要求が受信されたことをクライアントに通知します。
  • 3 回目のハンドシェイクでは、クライアントは接続を確認するために確認情報をサーバーに再度送信します。

ネットワークプログラミングの3つの要素

  1. プロトコル: コンピュータネットワーク通信が遵守しなければならない規則
  2. IP アドレス: 一般に IP として知られるインターネット プロトコル アドレスを指します。 IP アドレスは、ネットワーク上のコンピュータ デバイスに一意の番号を付けるために使用されます。
  • IPv4: 32 ビットの 2 進数で、通常は 4 バイトに分割され、192.168.65.100 などの abcd 形式で表されます。このうち、a、b、c、d はいずれも 0 ~ 255 の 10 進整数なので、最大 42 億まで表現できます。
  • 128 ビットのアドレス長を使用すると、16 バイトの各グループが ABCD:EF01:2345:6789:ABCD:EF01:2345:6789 として表現される 8 つの 16 進数グループに分割され、ネットワーク アドレス リソース不足の問題が解決されます。 。
    よく使用されるコマンド:
  • ipconfig [ローカルIPアドレスを表示]
    ここに画像の説明を挿入します
  • スペースの IP アドレスに ping [ネットワークが接続されているかどうかを確認]
  1. ポート番号
  • 2 バイトで表される整数。値の範囲は 0 ~ 65535 です。このうち、0 ~ 1023 のポート番号はいくつかの有名なネットワークで使用されています。
    ネットワーク サービスとアプリケーション、通常のアプリケーションは 1024 を超えるポート番号を使用する必要があります。ポート番号が別のサービスまたはアプリケーションによって占有されている場合、現在のプログラムは起動できません。
    ネットワーク内のプロセスを特定します。 协议 + IP地址 + 端口号

TCP通信プログラム

TCP通信能实现两台计算机之间的数据交互,通信的两端,要严格区分为客户端(Client)与服务端(Server)。

コミュニケーション手順

  • サーバープログラムは事前に起動する必要があり、クライアントの接続を待ちます。
  • クライアントはサーバーにアクティブに接続し、接続が成功した場合にのみ通信できます。サーバーはクライアントにアクティブに接続できません。

Java では、TCP 通信プログラムを実装するために 2 つのクラスが提供されています。

  1. クライアント: java.net.Socket クラスによって表されます。 Socket オブジェクトを作成し、サーバーに接続リクエストを送信すると、サーバーがリクエストに応答し、両者は接続を確立して通信を開始します。
  2. サーバー: java.net.ServerSocket クラスによって表されます。 ServerSocket オブジェクトの作成は、サービスを開始してクライアントの接続を待つことと同じです。

ソケットクラス

Socket 类:该类实现客户端套接字,套接字指的是两台设备之间通讯的端点。
施工方法:
public Socket(String host, int port) :ソケット オブジェクトを作成し、指定されたホスト上の指定されたポート番号に接続します。指定されたホストが null の場合、指定されたアドレスがループバック アドレスであることと同じになります (ループバック アドレス (127.xxx) はローカル ループバック アドレス (Loopback Address) です。)。
メンバーメソッド:

  • public InputStream getInputStream() : このソケットの入力ストリームを返します。
  • public OutputStream getOutputStream() : このソケットの出力ストリームを返します。
  • public void close() : このソケットを閉じます。
  • public void shutdownOutput() : このソケットの出力ストリームを無効にします。

サーバーソケットクラス

ServerSocket 类:这个类实现了服务器套接字,该对象等待通过网络的请求。
施工方法:
public ServerSocket(int port): ServerSocket オブジェクトの作成時に、このコンストラクターをポインターにバインドするために使用します。
特定のポート番号では、パラメータ port がポート番号になります。
メンバーメソッド:
public Socket accept() : 接続をリッスンして受け入れ、クライアントとの通信用に新しい Socket オブジェクトを返します。この方法
接続が確立されるまでブロックされます。

簡易TCPネットワークプログラム

TCP通信分析:

  1. [サーバー] 起動し、ServerSocketオブジェクトを作成し、接続を待ちます。
  2. [クライアント] 起動し、Socketオブジェクトを作成し、接続を要求します。
  3. [サーバー] は接続を受信し、accept メソッドを呼び出し、Socket オブジェクトを返します。
  4. [クライアント] SocketオブジェクトでOutputStreamを取得し、サーバーにデータを書き込みます。
  5. [サーバー] SocketオブジェクトでInputStreamを取得し、クライアントから送信されたデータを読み込みます。
  6. [サーバー] Socket オブジェクトを取得し、OutputStream を取得して、クライアントにデータを書き込みます。
  7. [クライアント] Scoket オブジェクト。InputStream を取得し、解析してデータを書き戻します。
  8. [クライアント] リソースを解放し、切断します。

コード例:

  • サービスターミナル:
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerTCP {
    public static void main(String[] args) throws IOException {
        System.out.println("服务端启动 , 等待连接 .... ");
        // 1.创建 ServerSocket对象,绑定端口,开始等待连接
        ServerSocket ss = new ServerSocket(6666);
        // 2.接收连接 accept 方法, 返回 socket 对象.
        Socket server = ss.accept();
        // 3.通过socket 获取输入流
        InputStream is = server.getInputStream();
        // 4.一次性读取数据
        // 4.1 创建字节数组
        byte[] b = new byte[1024];
        // 4.2 据读取到字节数组中.
        int len = is.read(b);
        // 4.3 解析数组,打印字符串信息
        String msg = new String(b, 0, len);
        System.out.println(msg);
        //5.关闭资源.
        is.close();
        server.close();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

サーバーはポート番号を指定し、accept() メソッドを通じて Socket オブジェクトを取得し、クライアント オブジェクトを通じて入力ストリームを取得し、最後にデータを読み取り、クライアントから送信されるメッセージを待ちます。

  • クライアント
import java.net.Socket;

public class ClientTCP {
    public static void main(String[] args) throws Exception {
        System.out.println("客户端 发送数据");
        // 1.创建 Socket ( ip , port ) , 确定连接到哪里.
        Socket client = new Socket("localhost", 6666);
        // 2.获取流对象 . 输出流
        OutputStream os = client.getOutputStream();
        // 3.写出数据.
        os.write("你好么? tcp ,我来了".getBytes());
        // 4. 关闭资源 .
        os.close();
        client.close();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

クライアントの作成時に、接続の IP アドレスとポート番号を指定して、サーバーへの接続を容易にし、クライアントの Socket オブジェクトを通じて出力ストリームと出力データを取得します。
ここに画像の説明を挿入します

ファイルアップロード【拡張】

  1. [クライアント] ストリームを入力し、ハードディスクからファイルデータをプログラムに読み込みます。
  2. [クライアント] ストリームを出力し、ファイルデータをサーバーに書き込みます。
  3. [サーバー] ストリームを入力し、ファイルデータをサーバープログラムに読み込みます。
  4. [サーバー] ストリームを出力し、ファイルデータをサーバーのハードディスクに書き込みます。
  5. [サーバー] 出力ストリームを取得し、データを書き戻します。
  6. [クライアント] 入力ストリームを取得し、データを解析して書き戻します。

数据准备:test.jpgという名前のファイルをDドライブに置き、testフォルダーを作成します。

コード例:

  • サーバ
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class FileUpload_Server {
    public static void main(String[] args) throws IOException {
        System.out.println("服务器 启动..... ");
        // 1. 创建服务端ServerSocket
        ServerSocket serverSocket = new ServerSocket(6666);
        // 2. 循环接收,建立连接
        while (true) {
        Socket accept = serverSocket.accept();
            /* 3. socket对象交给子线程处理,进行读写操作Runnable接口中,只有一个run方法,使用lambda表达式简化格式 */
            new Thread(() -> {
                try (   //3.1 获取输入流对象
                        BufferedInputStream bis = new BufferedInputStream(accept.getInputStream());
                        //3.2 创建输出流对象, 保存到本地 .
                        FileOutputStream fis = new FileOutputStream("D:/test/" + System.currentTimeMillis() + ".jpg");
                        BufferedOutputStream bos = new BufferedOutputStream(fis)) {
                    // 3.3 读写数据
                    byte[] b = new byte[1024 * 8];
                    int len;
                    while ((len = bis.read(b)) != -1) {
                        bos.write(b, 0, len);
                    }

                    // 4.=======信息回写===========================
                    System.out.println("back ........");
                    OutputStream out = accept.getOutputStream();
                    out.write("上传成功".getBytes());
                    out.close();

                    //5. 关闭 资源
                    bos.close();
                    bis.close();
                    accept.close();
                    System.out.println("文件上传已保存");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

ここでは、最初にサーバー オブジェクトを作成し、while(true) を使用してサーバーへの継続的な接続を確保し、次にスレッドを開始して、ユーザーが大きなファイルをアップロードするときに、ファイルをアップロードする他のユーザーの効率が影響を受けないようにします。システムのミリ秒 + 「.jpg」を使用してファイル名を設定し、アップロード中に同じファイル名によってファイル名が上書きされないようにします。

  • クライアント
import java.io.*;
import java.net.Socket;

public class FileUpload_Client {
    public static void main(String[] args) throws IOException {
        // 1.创建流对象
        // 1.1 创建输入流,读取本地文件
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\test.jpg"));
        // 1.2 创建输出流,写到服务端
        Socket socket = new Socket("localhost", 6666);
        BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
        //2.写出数据.
        byte[] b = new byte[1024 * 8 ];
        int len ;
        while (( len = bis.read(b))!=-1) {
            bos.write(b, 0, len);
        }
        // 关闭输出流,通知服务端,写出数据完毕
        socket.shutdownOutput();
        System.out.println("文件发送完毕");   
        // 3. =====解析回写============
        InputStream in = socket.getInputStream();
        byte[] back = new byte[20];
        in.read(back);
        System.out.println(new String(back));
        in.close();
        // ============================
        // 4.释放资源
        socket.close();
        bis.close();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

ここに画像の説明を挿入します
ここに画像の説明を挿入します
ここでは、サーバーがユーザーから送信されたファイルをハードディスクに正常に保存したことがわかります。

Java 愛好家はこの記事について学ぶことを歓迎します。著者は今後もこの記事を更新し続けますので、注目して収集していただくことを楽しみにしています。 。 。