day40-網路編程02

来源:https://www.cnblogs.com/liyuelian/archive/2022/09/18/16705775.html
-Advertisement-
Play Games

Java網路編程02 4.TCP網路通信編程 基本介紹 基於客戶端--服務端的網路通信 底層使用的是TCP/IP協議 應用場景舉例:客戶端發送數據,服務端接收並顯示控制台 基於Scoket的TCP編程 4.1應用案例1:(使用位元組流) 編寫一個伺服器端,和一個客戶端 伺服器端在9999埠監聽 客戶 ...


Java網路編程02

4.TCP網路通信編程

  • 基本介紹
    1. 基於客戶端--服務端的網路通信
    2. 底層使用的是TCP/IP協議
    3. 應用場景舉例:客戶端發送數據,服務端接收並顯示控制台
    4. 基於Scoket的TCP編程

4.1應用案例1:(使用位元組流)

  1. 編寫一個伺服器端,和一個客戶端
  2. 伺服器端在9999埠監聽
  3. 客戶端連接到伺服器端,發送“hello,server”,然後退出
  4. 伺服器端接收到客戶端發送的信息,輸出,並結束

image-20220918165642571

客戶端思路:

1.連接服務端(ip,埠)

2.連接上後,生成socket,通過socket.getOutputStream()

3.通過輸出流,寫入數據到數據通道

package li.network.socket;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;

//發送"hello,server"給服務端
public class SocketTCP01Client {
    public static void main(String[] args) throws IOException {
        //1.連接服務端(ip,埠)
        Socket socket = new Socket(InetAddress.getLocalHost(), 9999);//連接服務端的主機的埠,在這裡是本機
        System.out.println("客戶端 socket返回=" + socket.getClass());

        //2.連接上後,生成socket,通過socket.getOutputStream()
        //  得到和 socket 對象關聯的輸出流對象
        OutputStream outputStream = socket.getOutputStream();

        //3.通過輸出流,寫入數據到數據通道
        outputStream.write("hello,server".getBytes());

        //4. 關閉流對象和socket(必須關閉)
        outputStream.close();
        socket.close();

        System.out.println("客戶端退出");
    }
}

伺服器端思路:

1.在本機的9999埠監聽,等待連接

2.當沒有客戶端連接9999埠時,程式將會阻塞,等待連接

3.通過socket.getInputStream()讀取客戶端寫入到數據通道的數據,顯示

package li.network.socket;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class SocketTCP01Server {
    public static void main(String[] args) throws IOException {
        // 1.在本機的9999埠監聽,等待連接
        // 要求在本機沒有其他服務在監聽9999
        // ServerSocket 可以通過 accept() 方法返回多個 Socket[多個客戶端連接伺服器的併發]
        ServerSocket serverSocket = new ServerSocket(9999);
        System.out.println("服務端在9999埠監聽,等待連接...");

        // 2.當沒有客戶端連接9999埠時,程式會阻塞,等待連接
        // 如果有客戶端連接則會返回一個socket對象,程式繼續

        Socket socket = serverSocket.accept();

        System.out.println("伺服器端 socket=" + socket.getClass());

        // 3.通過socket.getInputStream()讀取客戶端寫入到數據通道的數據,顯示
        InputStream inputStream = socket.getInputStream();

        // 4.IO讀取
        byte[] buf = new byte[1024];
        int readLen = 0;
        while ((readLen = inputStream.read(buf)) != -1) {
            System.out.println(new String(buf, 0, readLen));//根據實際讀取到的長度顯示內容
        }

        // 5. 關閉流對象和socket(必須關閉)
        inputStream.close();
        socket.close();
        serverSocket.close();//關閉serverSocket
    }
}
  1. 要先運行服務端,這裡顯示正在等待連接客戶端:
image-20220918165750028
  1. 再運行客戶端程式,得到一個socket,通過輸出流將數據寫入到數通道裡面,然後退出:
image-20220918165823508
  1. 伺服器端會通過輸入流不停地讀取,把數據輸出到控制臺上,然後關閉退出:
image-20220918165840071

4.2應用案例2:(使用位元組流)

  1. 編寫一個伺服器端,和一個客戶端
  2. 伺服器端在9999埠監聽
  3. 客戶端連接到伺服器端,發送“hello,server”,並接收伺服器端回發的“hello,client”,再退出
  4. 伺服器端接收到客戶端發送的信息然後輸出,併發送“hello,client”,再退出
image-20220918174130881

註意設置寫入結束標記socket.shutdownOutput(); 否則程式會認為還在寫入數據。

服務端Server:

package li.network.socket;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

@SuppressWarnings("all")
public class SocketTCP02Server {
    public static void main(String[] args) throws IOException {
        // 1.在本機的9999埠監聽,等待連接
        // 要求在本機沒有其他服務在監聽9999
        // ServerSocket 可以通過 accept() 方法返回多個 Socket[多個客戶端連接伺服器的併發]
        ServerSocket serverSocket = new ServerSocket(9999);
        System.out.println("服務端在9999埠監聽,等待連接...");

        // 2.當沒有客戶端連接9999埠時,程式會阻塞,等待連接
        // 如果有客戶端連接則會返回一個socket對象,程式繼續

        Socket socket = serverSocket.accept();

        System.out.println("伺服器端 socket=" + socket.getClass());

        // 3.獲取數據,通過socket.getInputStream()讀取客戶端寫入數據通道的數據,並顯示
        InputStream inputStream = socket.getInputStream();
        //IO讀取
        byte[] buf = new byte[1024];
        int readLen = 0;
        while ((readLen = inputStream.read(buf)) != -1) {
            System.out.println(new String(buf, 0, readLen));//根據實際讀取到的字元串長度顯示內容
        }

        // 4. 回話,寫入數據
        // 獲取socket相關的輸出流
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("hello,client".getBytes());
        //設置寫入結束標記
        socket.shutdownOutput();


        // 5. 關閉流對象和socket(必須關閉)
        inputStream.close();
        outputStream.close();
        socket.close();
        serverSocket.close();//關閉serverSocket
    }
}

客戶端Client:

package li.network.socket;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;

@SuppressWarnings("all")
//發送"hello,server"給服務端
public class SocketTCP02Client {
    public static void main(String[] args) throws IOException {
        //1.連接服務端(ip,埠)
        Socket socket = new Socket(InetAddress.getLocalHost(), 9999);//連接服務端的主機的埠,在這裡是本機
        System.out.println("客戶端 socket返回=" + socket.getClass());

        //2.連接上後,生成socket,通過socket.getOutputStream()
        //  得到和 socket 對象關聯的輸出流對象
        OutputStream outputStream = socket.getOutputStream();

        //3.通過輸出流,寫入數據到數據通道
        outputStream.write("hello,server".getBytes());
        //設置寫入結束標記
        socket.shutdownOutput();

        //4. 獲取數據
        // 獲取和socket相關聯的輸入流,並顯示
        InputStream inputStream = socket.getInputStream();
        byte[] buf = new byte[1024];
        int readLen = 0;
        while ((readLen = inputStream.read(buf)) != -1) {
            System.out.println(new String(buf, 0, readLen));
        }

        //5. 關閉流對象和socket(必須關閉)
        outputStream.close();
        inputStream.close();
        socket.close();

        System.out.println("客戶端退出");
    }
}
  1. 服務端等待客戶端連接:
image-20220918174438250
  1. 客戶端往數據通道寫入數據“hello,server,並接受到服務端發送的數據“hello,client”
image-20220918174502483
  1. 服務端接收到數據:
image-20220918174555801

4.3應用案例3:(使用字元流)

  1. 編寫一個服務端,一個客戶端
  2. 服務端在9999埠監聽
  3. 客戶端連接到服務端,發送“hello,server”,並接收到服務端會發的“hello,client”,然後退出
  4. 服務端接收到 客戶端發送的信息,輸出,併發送“hello,client”,再退出

思路答題與應用案例2一致,這裡要求使用字元流,那麼在拿到輸入/輸出字元流之後,使用轉換流,將其轉換為字元流即可。

PS:設置寫入結束標記:除了使用socket.shutdownOutput(); 還可以使用writer.newLine(),如果使用這種結束標誌的話,需要使用readLine()的方式讀取

註意點:如果使用的是字元流,需要我們手動刷新xx.flush();,否則數據不會寫入數據通道

服務端Server:

package li.network.socket;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

//使用字元流
@SuppressWarnings("all")
public class SocketTCP03Server {
    public static void main(String[] args) throws IOException {
        // 1.在本機的9999埠監聽,等待連接
        // 要求在本機沒有其他服務在監聽9999
        // ServerSocket 可以通過 accept() 方法返回多個 Socket[多個客戶端連接伺服器的併發]
        ServerSocket serverSocket = new ServerSocket(9999);
        System.out.println("服務端在9999埠監聽,等待連接...");

        // 2.當沒有客戶端連接9999埠時,程式會阻塞,等待連接
        // 如果有客戶端連接則會返回一個socket對象,程式繼續

        Socket socket = serverSocket.accept();

        System.out.println("伺服器端 socket=" + socket.getClass());

        // 3.獲取數據,通過socket.getInputStream()讀取客戶端寫入數據通道的數據,並顯示
        InputStream inputStream = socket.getInputStream();
        //IO讀取---使用字元流
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String s = bufferedReader.readLine();
        System.out.println(s);//輸出

        // 4. 回話,寫入數據
        // 獲取socket相關的輸出流
        OutputStream outputStream = socket.getOutputStream();
        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
        bufferedWriter.write("hello,client 字元流");
        bufferedWriter.newLine();//插入一個換行符,表示回覆內容的結束
        bufferedWriter.flush();//手動刷新


        // 5. 關閉流對象和socket(必須關閉)
        bufferedWriter.close();//關閉外層流
        bufferedReader.close();
        socket.close();
        serverSocket.close();//關閉serverSocket
    }
}

客戶端Client:

package li.network.socket;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;

@SuppressWarnings("all")
//發送"hello,server"給服務端,使用字元流
public class SocketTCP03Client {
    public static void main(String[] args) throws IOException {
        //1.連接服務端(ip,埠)
        Socket socket = new Socket(InetAddress.getLocalHost(), 9999);//連接服務端的主機的埠,在這裡是本機
        System.out.println("客戶端 socket返回=" + socket.getClass());

        //2.連接上後,生成socket,通過socket.getOutputStream()
        //  得到和 socket 對象關聯的輸出流對象
        OutputStream outputStream = socket.getOutputStream();

        //3.通過輸出流,寫入數據到數據通道----使用字元流
        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
        bufferedWriter.write("hello,server 字元流");
        bufferedWriter.newLine();//插入一個換行符,表示寫入的內容結束,註意:要求對方使用readLine()!!!!
        //如果使用的是字元流,需要我們手動刷新,否則數據不會寫入數據通道
        bufferedWriter.flush();


        //4. 獲取數據
        // 獲取和socket相關聯的輸入流,並顯示
        InputStream inputStream = socket.getInputStream();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String s = bufferedReader.readLine();
        System.out.println(s);

        //5. 關閉流對象和socket(必須關閉)
        bufferedReader.close();//關閉外層流
        bufferedWriter.close();
        socket.close();

        System.out.println("客戶端退出");
    }
}
image-20220918183512374 image-20220918183527148 image-20220918183544508

4.4應用案例4:

  1. 編寫一個服務端和一個客戶端
  2. 伺服器端在埠8888監聽
  3. 客戶端連接到服務端,併發送一張圖片
  4. 伺服器端接收到客戶端發送的圖片,保存到src目錄下,然後發送“收到圖片”,再退出
  5. 客戶端接收到服務端的回話:“收到圖片“ 之後,再退出
  6. 該程式要求使用StreamUtils.java

說明:使用BufferedInputStreasm和BufferedOutputStream位元組流

思路如下:

  1. 客戶端這邊先將數據傳輸到客戶端程式中,然後通過socket獲取數據通道,將文件數據發送給服務端;

  2. 服務端這邊,先是得到數據通道上的數據(傳輸到服務端程式中),然後使用將程式中的文件數據輸出到某個目錄下,之後在將“收到圖片”的消息輸出到數據通道上

  3. 客戶端通過socket,從數據通道上獲取回覆消息,並列印在控制臺上

工具類StreamUtils:

package li.network.upload;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

/**
 * 此類用於演示關於流的讀寫方法
 *
 */
public class StreamUtils {
   /**
    * 功能:將輸入流轉換成byte[],即可以把文件的內容寫入到byte[]
    * @param is
    * @return
    * @throws Exception
    */
   public static byte[] streamToByteArray(InputStream is) throws Exception{
      ByteArrayOutputStream bos = new ByteArrayOutputStream();//創建輸出流對象
      byte[] b = new byte[1024];//位元組數組
      int len;
      while((len=is.read(b))!=-1){//迴圈讀取
         bos.write(b, 0, len);//把讀取到的數據寫入到 bos流中
      }
      byte[] array = bos.toByteArray();//然後將bos 轉成為一個位元組數組
      bos.close();
      return array;
   }

   /**
    * 功能:將InputStream轉換成String
    * @param is
    * @return
    * @throws Exception
    */
   
   public static String streamToString(InputStream is) throws Exception{
      BufferedReader reader = new BufferedReader(new InputStreamReader(is));
      StringBuilder builder= new StringBuilder();
      String line;
      while((line=reader.readLine())!=null){ //當讀取到 null時,就表示結束
         builder.append(line+"\r\n");
      }
      return builder.toString();
      
   }

}

服務端Server:

package li.network.upload;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

//文件上傳的服務端
public class TCPFileUploadServer {
    public static void main(String[] args) throws Exception {

        // 1.服務端在監聽8888埠(這裡是在本機進行)
        ServerSocket serverSocket = new ServerSocket(8888);
        System.out.println("服務端在8888埠監聽...");
        // 2.等待連接
        Socket socket = serverSocket.accept();

        //3.讀取數據通道的數據
        //通過socket獲得輸入流
        //創建對象
        BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
        //寫入到程式中
        byte[] bytes = StreamUtils.streamToByteArray(bis);//streamToByteArray方法:將輸入流轉換成byte[]

        //4.將得到的bytes數組(文件數據)寫入到指定的路徑,就得到一個文件
        String destFilePath = "src\\copy.png";
        //創建對象
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFilePath));
        //寫入數據到目錄中
        bos.write(bytes);
        bos.close();

        //5.收到圖片後,向客戶端回覆“收到圖片”
        //通過socket獲得輸出流
        //創建對象
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        bw.write("收到圖片");
        bw.flush();//把內容刷新到數據通道
        socket.shutdownOutput();//設置寫入結束標記

        //6.關閉其他資源
        bw.close();
        bis.close();
        socket.close();
        serverSocket.close();
    }
}

客戶端Client:

package li.network.upload;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.Socket;

//文件上傳的客戶端
public class TCPFileUploadClient {
    public static void main(String[] args) throws Exception {
        //1.客戶端連接服務端,得到一個socket對象
        Socket socket = new Socket(InetAddress.getLocalHost(), 8888);

        //2.創建讀取磁碟文件的輸入流
        String filePath = "d:\\ggmm.jpg";
        //創建對象
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath));
        //這裡的 bytes 就是 文件filePath 對應的位元組數組
        //讀取數據到程式中
        byte[] bytes = StreamUtils.streamToByteArray(bis);

        //3.通過socket獲取輸出流,將bytes數據發送到服務端
        //創建對象
        BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
        //寫入數據通道
        bos.write(bytes);//將文件對應的位元組數組寫入到數據通道
        bis.close();
        socket.shutdownOutput();//設置寫入數據的結束標誌

        //4.獲取服務端回覆的消息
        InputStream inputStream = socket.getInputStream();
        String s = StreamUtils.streamToString(inputStream);//streamToString方法:把一個輸入流的數據直接轉成字元串
        System.out.println(s);

        //關閉相關的流
        inputStream.close();
        bos.close();
        socket.close();
    }
}

image-20220918202653847 image-20220918202750982

image-20220918202841610 image-20220918202833159


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 我的設計模式之旅。本節詳細說明單例模式的實現方式、優缺點,簡要描述多線程情況下利用雙重鎖定保護單例對象和C#靜態初始化的方式。並用 Golang 實現單例模式,三個工作者需要各自找到電梯搭乘,只有一個電梯!補充C#單線程單例模式的實現。 ...
  • 目錄 一.OpenGL 圖像反色 1.原始圖片 2.效果演示 二.OpenGL 圖像反色源碼下載 三.猜你喜歡 零基礎 OpenGL ES 學習路線推薦 : OpenGL ES 學習目錄 >> OpenGL ES 基礎 零基礎 OpenGL ES 學習路線推薦 : OpenGL ES 學習目錄 >> ...
  • 我的博客 俗話說,工欲善其事必先利其器,所以在使用日期前要先對日期進行處理,所以時間戳和字元串的來回來去轉換這個事肯定是要搞的 這次的函數有一個?有兩個?有三個?有四個!上代碼! 哈哈,像不像直播帶貨 本次用到3個內置包 import reimport timeimport calendar 第一個 ...
  • 1. auth模塊 在創建完django項目之後,執行資料庫遷移之後,資料庫里會增加很多新表,其中有一張名為auth_user的表,當訪問django自帶的路由admin的時候,需要輸入用戶名和密碼,其參照的就是auth_user表 使用python3 manage.py crataesupperu ...
  • 在Spring的簡介中我們知道了Spring的核心是控制反轉(ICO)和麵向切麵編程(AOP),我們不直接對ICO進行學習,而是先學習ICO的理論推導。 這是我一個maven項目的結構。 UserDao: package com.jms.dao; public interface UserDao { ...
  • 操作步驟 先設置輸入路徑與輸出路徑 輸入路徑:需要被轉換的文件路徑 輸出路徑:轉換後的文件儲存路徑 我沒有寫這個屬性的交互操作,只是在第一行用字面量進行設置 如果輸出路徑的目錄不存在,則就會進行交互,是否創建該目錄,如果不創建就退出程式 再是選擇字元集轉換的類型,是全部文件預設使用同一套字元集轉換, ...
  • **註:**本文所有函數名為中文名,並不符合代碼規範,僅供讀者理解參考。 Goroutine Go程不是OS線程,也不是綠色線程(語言運行時管理的線程),而是更高級別的抽象,一種特殊的協程。是一種非搶占式的簡單併發子goroutine(函數、閉包、方法)。不能被中斷,但有多個point可以暫停或重新 ...
  • 左值引用是已定義的變數的別名,其主要用途是用作函數的形參,將 const 關鍵字用於左值引用時,其在初始化時可接受的賦值形式變得更加廣泛了,這裡來總結一下。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...