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
  • 概述:本文代碼示例演示瞭如何在WPF中使用LiveCharts庫創建動態條形圖。通過創建數據模型、ViewModel和在XAML中使用`CartesianChart`控制項,你可以輕鬆實現圖表的數據綁定和動態更新。我將通過清晰的步驟指南包括詳細的中文註釋,幫助你快速理解並應用這一功能。 先上效果: 在 ...
  • openGauss(GaussDB ) openGauss是一款全面友好開放,攜手伙伴共同打造的企業級開源關係型資料庫。openGauss採用木蘭寬鬆許可證v2發行,提供面向多核架構的極致性能、全鏈路的業務、數據安全、基於AI的調優和高效運維的能力。openGauss深度融合華為在資料庫領域多年的研 ...
  • openGauss(GaussDB ) openGauss是一款全面友好開放,攜手伙伴共同打造的企業級開源關係型資料庫。openGauss採用木蘭寬鬆許可證v2發行,提供面向多核架構的極致性能、全鏈路的業務、數據安全、基於AI的調優和高效運維的能力。openGauss深度融合華為在資料庫領域多年的研 ...
  • 概述:本示例演示了在WPF應用程式中實現多語言支持的詳細步驟。通過資源字典和數據綁定,以及使用語言管理器類,應用程式能夠在運行時動態切換語言。這種方法使得多語言支持更加靈活,便於維護,同時提供清晰的代碼結構。 在WPF中實現多語言的一種常見方法是使用資源字典和數據綁定。以下是一個詳細的步驟和示例源代 ...
  • 描述(做一個簡單的記錄): 事件(event)的本質是一個委托;(聲明一個事件: public event TestDelegate eventTest;) 委托(delegate)可以理解為一個符合某種簽名的方法類型;比如:TestDelegate委托的返回數據類型為string,參數為 int和 ...
  • 1、AOT適合場景 Aot適合工具類型的項目使用,優點禁止反編 ,第一次啟動快,業務型項目或者反射多的項目不適合用AOT AOT更新記錄: 實實在在經過實踐的AOT ORM 5.1.4.117 +支持AOT 5.1.4.123 +支持CodeFirst和非同步方法 5.1.4.129-preview1 ...
  • 總說周知,UWP 是運行在沙盒裡面的,所有許可權都有嚴格限制,和沙盒外交互也需要特殊的通道,所以從根本杜絕了 UWP 毒瘤的存在。但是實際上 UWP 只是一個應用模型,本身是沒有什麼許可權管理的,許可權管理全靠 App Container 沙盒控制,如果我們脫離了這個沙盒,UWP 就會放飛自我了。那麼有沒... ...
  • 目錄條款17:讓介面容易被正確使用,不易被誤用(Make interfaces easy to use correctly and hard to use incorrectly)限制類型和值規定能做和不能做的事提供行為一致的介面條款19:設計class猶如設計type(Treat class de ...
  • title: 從零開始:Django項目的創建與配置指南 date: 2024/5/2 18:29:33 updated: 2024/5/2 18:29:33 categories: 後端開發 tags: Django WebDev Python ORM Security Deployment Op ...
  • 1、BOM對象 BOM:Broswer object model,即瀏覽器提供我們開發者在javascript用於操作瀏覽器的對象。 1.1、window對象 視窗方法 // BOM Browser object model 瀏覽器對象模型 // js中最大的一個對象.整個瀏覽器視窗出現的所有東西都 ...