Java網路編程基礎

来源:https://www.cnblogs.com/keruanren/archive/2023/10/09/17753087.html
-Advertisement-
Play Games

Java網路編程基於TCP/UDP協議的基礎之上,TCP/IP協議是一個協議簇。裡面包括很多協議的,UDP只是其中的一個, 之所以命名為TCP/IP協議,因為TCP、IP協議是兩個很重要的協議,就用他兩命名了。那麼首先我們先介紹一下TCP和UDP的特點: 1.TCP(Transmission Con ...


Java網路編程基於TCP/UDP協議的基礎之上,TCP/IP協議是一個協議簇。裡面包括很多協議的,UDP只是其中的一個, 之所以命名為TCP/IP協議,因為TCP、IP協議是兩個很重要的協議,就用他兩命名了。那麼首先我們先介紹一下TCP和UDP的特點:

1.TCP(Transmission Control Protocol,傳輸控制協議)是面向連接的,也就是說在以TCP協議發送數據的之前需要兩台主機建立連接,一個TCP連接必須要經過三次“對話”才能建立起來,也俗稱“三次握手”,其中的過程非常複雜,下麵將以簡單的形式介紹一下三次握手的過程:

有兩台主機,主機A與主機B。

1)主機A向主機B發出連接請求數據包:“我想給你發數據,可以嗎?”,這是第一次對話;

2)主機B向主機A發送同意連接和要求同步 (同步就是兩台主機一個在發送,一個在接收,協調工作)的數據包 :“可以,你什麼時候發?”,這是第二次對話;

3)主機A再發出一個數據包確認主機B的要求同步:“我現在就發,你接著吧!”, 這是第三次對話。

三次“對話”的目的是使數據包的發送和接收同步, 經過三次“對話”之後,主機A才向主機B正式發送數據。

TCP建立連接需要三次握手,而斷開連接需要四次,即四次揮手:

1)主機A向主機B發送請求斷開連接,這是第一次對話;

2)主機B收到主機A的斷開連接請求,返回確認,這是第二次對話;

3)主機B在接收完所有數據之後,向主機A發送確認斷開連接,這是第三次對話;

4)主機A回覆確認斷開,這是第四次對話;

這四次對話完成之後,主機A和主機B才正式斷開連接。

2.UDP(User Data Protocol,用戶數據報協議),與TCP相反,UDP是不面向連接的協議,所以也是不可靠傳輸,只能儘力傳輸數據而保證數據傳輸的可靠性,常用於視頻會議或者消息發送等服務。

瞭解了基本的概念特點之後,我們將使用Java編程的方式來實現基於這兩種協議的數據傳輸過程:

UDP

傳輸數據與我們生活中寄快遞很相似,在寄快遞的時候,我們首先要用一個盒子將物品打包起來,再通過物流公司寄送出去,那麼傳輸數據也是類似的:

首先client,DatagramSocket對象就類似與快遞公司,負責最後的物品寄送,DatagramPacket對象就類似於打包過程,將所需要的數據進行打包。

 1 public class SendMessageDemo {
 2     public static void main(String[] args) throws IOException {
 3         //採用UDP協議發送數據
 4         //1.創建DatagramSocket對象(快遞公司,負責發送數據)
 5         //空參 隨機綁定一個埠號進行使用 有參則指定埠號進行綁定
 6         DatagramSocket ds = new DatagramSocket();
 7         InetAddress address = InetAddress.getByName("127.0.0.1");
 8         int port = 10087;
 9         //2.打包數據,用位元組數組的形式發送
10         String str = "Hello world!";
11         byte[] bytes = str.getBytes();
12         DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);
13         //3.發送數據
14         ds.send(dp);
15         //4.釋放資源
16         ds.close();
17 
18     }
19 }

對於Server端,接收到client發送的數據之後,需要對這些位元組進行解析,才能夠知道發送的是什麼內容:

 1 public class ReceiveMessageDemo {
 2     public static void main(String[] args) throws IOException {
 3         //先運行接收進程,再運行發送進程
 4         //創建快遞公司用來接收數據包,必須綁定跟發送端發送的埠一致
 5         DatagramSocket ds = new DatagramSocket(10087);
 6 
 7         //2.接收數據包
 8         byte[] bytes = new byte[1024];
 9         //使用空的數據包存儲數據
10         DatagramPacket dp = new DatagramPacket(bytes,bytes.length);
11         //該方法是阻塞的,會一直等待發送方發送消息
12         ds.receive(dp);
13 
14         //3.解析數據包
15         byte[] data = dp.getData();//獲取接收到的數據
16         int length = dp.getLength();//獲取接收到的數據的長度
17         String str = new String(data,0,length);//解析成字元串的形式
18         InetAddress address = dp.getAddress();//獲取發送方的IP信息
19         int port = dp.getPort();
20         System.out.println("接收到的信息為:"+str+",來自主機:"+address+"埠為:"+port);
21         System.out.println("長度為:"+length);
22 
23 
24     }
25 }

如果想發送多條消息呢?我們可以使用while迴圈來接收用戶鍵盤輸入的消息:

 1 public class SendMessageAgent {
 2     public static void main(String[] args) throws IOException {
 3 
 4         //發送方埠可以不指定隨機使用
 5         DatagramSocket ds = new DatagramSocket();
 6 
 7         //創建要發送的數據包
 8         Scanner scanner = new Scanner(System.in);
 9         while(true) {
10             System.out.println("請輸入你要發送的內容:");
11             String s = scanner.nextLine();
12             if (s.equals("886")) {
13                 break;
14             }
15             //將輸入的字元串轉為位元組數組發送
16             byte[] message = s.getBytes();
17 
18             //選擇發送的主機和埠
19             InetAddress address = InetAddress.getByName("127.0.0.1");
20             int port = 10088;
21             DatagramPacket dp = new DatagramPacket(message, message.length, address, port);
22 
23             //發送
24             ds.send(dp);
25         }
26         //釋放資源
27         ds.close();
28     }
29 }

TCP

如果要使用TCP協議發送數據,那麼和UDP所需要的對象是不一樣的:

 1 public class Client {
 2     public static void main(String[] args) throws IOException {
 3         //TCP協議
 4         //1.創建socket對象
 5         //該對象綁定需要連接的主機與埠,如果連接失敗則代碼報錯
 6         Socket socket = new Socket("127.0.0.1",10000);
 7 
 8         //TCP中以IO輸出流的形式發送,以輸入流的形式接收
 9         //2.獲取輸出流,並寫入數據
10         OutputStream os = socket.getOutputStream();
11         os.write("hello world!你們好".getBytes());
12 
13         //釋放資源 這裡進行四次揮手
14         os.close();
15         socket.close();
16 
17     }
18 }
public class Server {
    public static void main(String[] args) throws IOException {

        //1.創建serverSocket,並綁定接收埠(必須與發送的埠相同)
        ServerSocket socket = new ServerSocket(10000);

        //2.監聽連接,如果連接成功則返回一個socekt對象,沒有連接成功則阻塞等待
        Socket accept = socket.accept();//這裡進行三次握手

        //3.從accept中讀取輸入流,並獲取信息
        InputStream is = accept.getInputStream();
        //位元組流,一個位元組一個位元組的讀入,但是中文會出錯,一個中文三個位元組,讀入的時候會導致中文亂碼
        InputStreamReader isr = new InputStreamReader(is);//字元流,一個字元一個字元的讀入,解決中文問題
        BufferedReader br = new BufferedReader(isr);//提升讀取效率
        int b;
        while((b=br.read()) != -1){//需要定義結束標記,不然會一直卡死在這裡等待讀取
            System.out.print((char) b);
        }
        //收到信息後寫入反饋
        InetAddress address = accept.getInetAddress();
        OutputStream outputStream = accept.getOutputStream();
        String returnMessage = "已經收到:"+address.getHostAddress()+address.getHostName()+"發來的信息!";
        outputStream.write(returnMessage.getBytes());
        //4.釋放資源
        accept.close();
        socket.close();
    }
}

需要先運行server端代碼,再運行client端代碼,因為client端如果沒有找到對應主機則會報錯。

 文件傳輸

client端:

 1 public class client {
 2     public static void main(String[] args) throws IOException {
 3         Socket socket = new Socket("127.0.0.1",10000);
 4 
 5         BufferedInputStream bis = new BufferedInputStream(new FileInputStream("mysocketnet/clientdir/neural.png"));
 6         BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
 7 
 8         byte[] bytes = new byte[1024];
 9         int len;
10         while((len=bis.read(bytes)) != -1){
11             bos.write(bytes,0,len);
12         }
13 
14         socket.shutdownOutput();
15         //獲取伺服器的回寫數據
16         BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
17         String line = br.readLine();
18         System.out.println(line);
19 
20         socket.close();
21     }
22 }

通過多線程來解決多用戶同時上傳文件的問題,每有一個用戶建立連接就新創建一個線程來處理上傳文件的請求,可以採用線程池進行優化,採用runnable的方式創建線程,這樣我們可以定義自己的runnable方法來處理文件上傳請求:

 1 public class server {
 2     public static void main(String[] args) throws IOException {
 3 
 4         ServerSocket serverSocket = new ServerSocket(10000);
 5         Socket accept = serverSocket.accept();
 6         //每建立一個連接,就創建一個線程來處理上傳請求!
 7         //創建線程池對象
 8         ThreadPoolExecutor pool = new ThreadPoolExecutor(
 9                 3,//核心線程數量
10                 16,//線程池總大小
11                 60,//空閑時間
12                 TimeUnit.SECONDS,
13                 new ArrayBlockingQueue<Runnable>(2),
14                 Executors.defaultThreadFactory(),
15                 new ThreadPoolExecutor.AbortPolicy()
16         );
17         //new Thread(new SocketRunnable(accept) ).start();
18         pool.submit(new SocketRunnable(accept));
19 
20     }
21 }
public class SocketRunnable implements Runnable{
    Socket accept;
    public SocketRunnable(Socket accept){
        this.accept = accept;
    }
    @Override
    public void run() {
        try {
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("mysocketnet/serverdir/neural.png"));
            BufferedInputStream bis = new BufferedInputStream(accept.getInputStream());

            byte[] bytes = new byte[1024];
            int len;
            while ((len = bis.read(bytes)) != -1) {
                bos.write(bytes, 0, len);
            }
            //回寫數據
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(accept.getOutputStream()));
            bw.write("上傳成功!");
            bw.newLine();
            bw.flush();
        }catch (Exception e){
            System.out.println("上傳失敗");
        }finally {
            try {
                if(accept != null){
                accept.close();}
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

 


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

-Advertisement-
Play Games
更多相關文章
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 前端換膚方案 - element+less無感換膚(無需頁面刷新) 前言 前不久在改造一個迭代了一年多的項目時,增加了一個換膚功能。通過自己的探索,總結出了一套比較合適的改造方案供大家參考,如有更好的方案歡迎評論區踴躍評論😄 先上效果: ...
  • three.js、webgl、3D煤礦隧道、三維井下人員定位、掘進面三維可視化、縱採面可視化、採集面可視化展示、設備檢測、數字孿生、物聯網3D、3d建築、3d庫房,bim管理系統 ...
  • 導讀 VTable: 不只是高性能的多維數據分析表格,更是行列間創作的方格藝術家! VTable是位元組跳動開源可視化解決方案 VisActor 的組件之一。 在現代應用程式中,表格組件是不可或缺的一部分,它們能夠快速展示大量數據,並提供良好的可視化效果和交互體驗。VTable是一款基於可視化渲染引擎 ...
  • 單例模式 一個類只有一個實例,並提供一個全局訪問此實例的點,哪怕多線程同時訪問。 單例模式主要解決了一個全局使用的類被頻繁的創建和消費的問題。 單例模式的案例場景 資料庫的連接池不會反覆創建 spring中一個單例模式bean的生成和使用 在我們平常的代碼中需要設置全局的一些屬性保存 七種單例模式的 ...
  • 本文介紹了一種基於線上流量實現對重構系統進行功能和性能驗證的實踐方案。針對線上流量如何攔截、如何錄製、如何存儲、如何回放以及如何發壓均作了詳細說明,為具有類似需求的讀者提供了一種可供參考的思路。 ...
  • 一起學習下架構的視角。 架構的視角 在筆者的知識體系中,實際上將架構分為業務架構、應用架構、雲基礎架構這幾大類,業務架構主要著眼於控制業務的複雜性,基礎架構著眼於解決分散式系統中存在的一系列問題。無論何種架構,都希望能實現系統的可變的同時保障業務的高可用。 很多時候架構的視角/分類沒有明顯的邊界,通 ...
  • 一、項目地址 https://github.com/LinFeng-BingYi/DailyAccountBook 二、新增 1. 在表格中設置選項列表,讓用戶更快地編輯動賬記錄 1.1 功能詳述 為表格中以下欄位設置選項列表: 1. 需求強度(由"基本需求"更名) 溫飽:基本維持生存且不鋪張浪費的 ...
  • Python裝飾器是一種語法糖,用於在不改變原有函數代碼的情況下,為函數添加額外的功能。裝飾器本質上是一個函數,它接收一個函數作為參數,並返回一個新的函數,通常使用@語法糖來應用裝飾器。 1.裝飾器本質是一個函數,可稱之為函數裝飾器; 2.裝飾器也是一個閉包,即在非全局範圍內定義的函數可以引用其外圍... ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...