【Stream—7】NetworkStream相關知識分享

来源:https://www.cnblogs.com/xiaomowang/archive/2019/11/27/11941041.html
-Advertisement-
Play Games

一、NetworkStream的作用 和先前的流有所不同,NetworkStream的特殊性可以在它的命名空間中得以瞭解(System.Net.Sockets),聰明的你馬上就會反應過來:既然是在網路中傳輸的流,那必然有某種協議或者規則約束他,不錯,這種協議就是Tcp/Ip協議。這個是什麼東西?別急 ...


一、NetworkStream的作用

和先前的流有所不同,NetworkStream的特殊性可以在它的命名空間中得以瞭解(System.Net.Sockets),聰明的你馬上就會反應過來:既然是在網路中傳輸的流,那必然有某種協議或者規則約束他,不錯,這種協議就是Tcp/Ip協議。這個是什麼東西?別急,我先讓大家瞭解以下NetworkStream的作用:如果伺服器和客戶端之間基於TCP連接的,他們之間能夠依靠一個穩定的位元組流進行相互傳輸信息,這也是NetworkStream的最關鍵的作用,有了這個神奇的協議,NetworkStream便能向其他流一樣在網路中(進行點對點的傳輸),這種傳輸的效率和速度是非常高的(UDP也很快,稍後再介紹),如果大家對這個概念還不是很清晰的話,別怕,後文中我會更詳細的說明。

這裡有5點大家先瞭解以下就行:

1、NetworkStream只能在具有TCP/IP協議之中,如果用在UDP中編譯不報錯,會報異常。

2、NetworkStream是面向連接的。

3、在網路中利用流的形式傳遞信息。

4、必須藉助Socket(也稱之為流式socket),或者使用一些返回的返回值,例如TcpClient類的GetStream方法。

5、用法和普通流方法幾乎一模一樣,但具有特殊性。

二、簡單介紹一下TCP/IP協議和相關層次

提到協議相信許多初學者或者沒搞過這塊的朋友會一頭霧水,不過別怕,協議也是人定的,肯定能搞懂:

其實協議可以這麼理解,是人為制定的為某個活動定義的一系列規則和約束,就好比足球比賽的紅牌黃牌,這是由世界足聯制定的協議或者規範,一旦不按這個協議,足球賽肯定會一片混亂。

進入正題:

TCP/IP

全稱:Transmission Control Protocol/Internet Protocol(傳輸控制協議/網際網路互聯協議,又名網路通訊協議)

這個便是互聯網通信中的最基本協議,tcp/ip定義了電子設備如何進入到互聯網,以及數據如何在互聯網中傳遞。既然有了協議,但是空頭支票還是不行的,就好比足聯制定了這些規則,但是沒有裁判在球場上來實施這些規則一樣,tcp/ip協議也有它自己的層次結構,關於他的層次結構,大家看圖就能明白:

 

 發送數據:

大家不用刻板的取理解這個協議,我還是用我們最普通的瀏覽網頁來給大家講解一下,首先,打開瀏覽器輸入一個Url,這時候,應用成會判斷這個要求是否是http的,然後,http會將請求信息交給傳輸層來執行,傳輸層主要負責信息流的格式化並且提供一個可靠的傳輸,這時候,TCP和UDP這兩個協議在這裡起作用了,TCP協議規定:接收端必鬚髮回確認,並且加入分組丟失,必須重新發送,接著網路層得到這些需要發送的數據,(網路中的IP協議非常重要,不僅是IP協議,還有ARP協議(查找遠程主機MAC地址)),這時候網路層會命令網路介面層取發送這些信息(IP層主要負責的是在節點之間的數據報傳送,這裡的節點是一臺網路設備,比如電腦,大家便可以理解為網路介面層的設備),最終將請求數據發送至遠程網站主機後等待遠程主機發送來信息。

接收數據:

好了,遠程網站主機會根據請求信息(ip,數據報等等)發送一系列的網頁數據通過網線或者無線路由,回到網路介面層,然後逐級上報,通過網路層的IP然後通過傳輸層的一系列格式化,最終通過http返回至瀏覽器顯示網頁了。

基於篇幅的關係,還有其他的協議大家可以自行去瞭解學習,相信園子里很多大神都寫過關於http協議的博文,大家也可以去學習一下。

三、簡單說明一下TCP和UDP的區別

TCP:

1、TCP是面向連接的通信協議,通過三次握手建立連接

2、TCP提供的是一種可靠的數據流服務,採用“帶重傳的肯定確認”技術來實現傳輸的可靠性

UDP:

1、UDP是面向無連接的通信協議,UDP數據包括目的埠號和源埠號信息,由於通訊不需要連接,所以可以實現廣播發送

2、UDP通訊時,不需要接受方確認,屬於不可靠傳輸,可能會出現丟包現象,實際應用中要求在程式員編程驗證。

3、由於上述2點的關係,UDP傳輸速度更快,但是安全性比較差,很容易發生未知的錯誤,所以本章的NetworkStream無法使用在UDP的功能上。

四、簡單介紹下套接字(Socket)的概念

關於Socket的概念和功能可能可以寫很長的一篇文章來介紹,這裡大家把socket理解tcp/ip協議的抽象,並且能夠實現tcp/ip協議棧的工具就行,換句話說,我們可以利用socket實現客戶端和服務端雙向通信,同樣,對於socket最關鍵的理解還沒到位,很多新人或者不常用的朋友會問:socket功能到底時什麼?怎麼工作的?

再次舉個例子,女朋友打電話給我,我可以選擇接通或者拒絕,如果我接了她的電話,也就是說,我和她通過電話連接(Connect),那電話就是“Socket”,女友和我都可以時客戶端或者服務端,只要點對點就行,我們的聲音通過電話傳遞,但是具體傳輸內容不歸Socket管轄,Socket的直接任務可以歸納為以下幾點:

1、創建客戶端或服務端

2、服務端或客戶端監聽是否有服務端或客戶端傳來的連接信息(Listening)

3、創建點對點連接(Connect)

4、發送accept信息給對方,表示兩者已經建立連接,並且可以相互傳遞信息了(Send)

5、具體發送什麼信息內容不是Socket管轄的範圍,但是必須是Socket進行發送的動作

6、統里可以通過Socket去接收對方發來的信息,並加以處理

後面我們會簡單的寫一個Socket的示例

五、簡單介紹下TcpClient、TcpListener、IPEndPoint類的作用

1、TcpClient

此類事微軟基於Tcp封裝類,用於簡化Tcp客戶端的開發,主要通過構造帶入主機地址或者IPEndPoint對象,然後調用Connect進行和伺服器點對點的連接,連接成功後通過GetStream方法返回NetworkStream對象。

2、TcpListener

此類也是微軟基於Tcp封裝類,用於監聽伺服器或者客戶端的連接請求,一旦有連接請求信息,理解交給TcpClient的AcceptTcpClient方法捕獲,Start方法用於開始監聽。

3、IPEndPoint

處理IP地址和埠的封裝類

4、IPAddress

提供包含電腦在IP網路上的地址的工具類

六、使用NetworkStream的註意事項和局限性

從這裡開始,才真正的介紹NetworkStream,但前面的一再說明NetworkStream背後那個必須掌握的知識點,這樣才能在實際變成過程中很快上手,畢竟NetworkStream的工作環境和其他流有很大的差別,再回到第一節關於NetworkStream的知識點,在使用時有幾點必須註意:

1、再次強調NetworkStream是穩定的,面向連接的,所以它只適用TCP協議的環境下工作,所以一旦在UDP環境中,雖然編譯不會報錯,但是會跳出異常。

2、我們可以通過NetworkStream簡化Socket開發

3、如果要建立NetworkStream一個新的實例,則必須使用已經連接的Socket

4、NetworkStream使用後不會自動關閉提供的socket,必須使用NetworkStream構造函數時是定的socket所有權(NetworkStream的構造函數中設置)

5、NetworkStream支持非同步讀寫操作。

NetworkStream的局限性:

1、可惜的是NetworkStream基於安全上的考慮不支持Position屬性或Seek方法,尋找或改變流的位置,如果吃土強行使用會報出NotSupport的異常

2、支持傳遞數據的種類沒有直接使用Socket來的多。

七、NetworkStream的構造

1、NetworkStream(Socket socket):

為制定的Scoket創建NetworkStream類的新實例

2、NetworkStream(Socket socket,Boolean ownsSocket):

用來指定Socket所屬權為是定的Socket,ownsSocket表示指示NetworkStream是否擁有該Socket

3、NetworkStream(Socket socket,FileAccess fileAccess):

用指定的訪問許可權為指定的Socket創建FileAccess值得按位組合,這些值指定授予所低通得Scoket上的NetworkStream的訪問類型

4、NetworkStream(Socket socket,FileAccess fileAccess,Boolean ownsSocket):

以上就是NetworkStream常用的幾個構造

對於NetworkStream構造函數的理解相信大家經過前文的解釋也能夠掌握了,但是有幾點必須強調以下

1、如果用構造產生NetworkStream的實例,則必須使用連接的Socket

2、如果該NetworkStream擁有對Socket的所有權,則在使用NetworkStream的Close方法時,會同時關閉Socket,否則關閉NetworkStream時不會關閉Socket

3、能夠創建對指定Socket帶有讀寫許可權的NetworkStream

八、NetworkStream的屬性

1、CanSeek:用於指示流是否支持查找,它的值始終為false

2、DataAvailable:指示在要讀取的NetworkStream上是否有可用的數據,一般來說通過判斷這俄格屬性來判斷NetworkStream是否有數據

3、Length:NetworkStream不支持使用Length屬性,強行使用會發生NotSupportedException異常

4、Position:NetworkStream不支持使用Position屬性,強行使用會發生NotSupportedException異常

九、NetworkStream的方法

同樣,NetworkStream的方法大致重寫或繼承了Stream的方法,但是以下方法必須註意:

1、int Read(byte[] buffer,int offset,int size)

該方法將數據讀入buffer參數並返回成功讀取的位元組數,如果沒有可以讀取的數據,則Read方法返回0,Read操作將讀取儘可能多的可用數據,直至達到由size參數指定的位元組數為止。如果遠程主機關閉了連接並且已接受到所有可用數據,Read方法將立即完成並返回0位元組。

2、long Seek(long offset,SeekOrigin origin)

將流的當前位置設置為給定值,此方法當前不愁支持,總是引發NotSupportException

3、void Write(byte[] buffer,int offset,int size)

Write方法在指定的offset處啟動,並將buffer內容的size位元組發送到網路,Write方法將一直處於阻止狀態(可以用非同步解決),知道發送了請求的位元組數或引發SocktException為止,如果收到ScoketException,可以使用SocketException.ErrorCode屬性獲取特定的錯誤代碼。

十、NetworkStream的簡單示例

創建一個客戶端向服務端傳輸圖片的小示例

服務端一直監聽客戶端傳來的圖片信息

 服務端代碼:

 1     class Program
 2     {
 3         //全局tcpClient
 4         private static TcpClient _client;
 5         //文件流建立到磁碟上的讀寫流
 6         static FileStream fs=new FileStream("F:\\abc.jpg",FileMode.Create);
 7         //buffer
 8         private static int bufferlength = 200;
 9         private static byte[] buffer = new byte[bufferlength];
10         //網路流
11         private static NetworkStream _ns;
12         static void Main()
13         {
14             ConnectAndListen();
15            // Console.ReadKey();
16         }
17 
18         static void ConnectAndListen()
19         {
20             //服務端監聽任何Ip,但是埠號時80的連接
21             TcpListener listener=new TcpListener(IPAddress.Any,9090);
22             //監聽對象開始監聽
23             listener.Start();
24             while (true)
25             {
26                 Console.WriteLine("等待連接");
27                 //線程會掛在這裡,直到客戶端發來連接請求
28                 _client = listener.AcceptTcpClient();
29                 Console.WriteLine("已連接");
30                 //得到從客戶端傳過來的網路流
31                 _ns = _client.GetStream();
32                 //如果網路流中由數據
33                 if (_ns.DataAvailable)
34                 {
35                    //非同步讀取網路流中的byte信息
36                    _ns.BeginRead(buffer, 0, bufferlength, ReadAsyncCallBack, null);
37                 }
38             }
39         }
40 
41         /// <summary>
42         /// 非同步讀取回調函數
43         /// </summary>
44         /// <param name="result"></param>
45         static void ReadAsyncCallBack(IAsyncResult result)
46         {
47             int readCount;
48             //獲得每次非同步讀取數量
49             readCount = _client.GetStream().EndRead(result);
50             //如果全部讀完退出,垃圾回收
51             if (readCount<1)
52             {
53                 _client.Close();
54                 _ns.Dispose();
55                 fs.Dispose();
56                 return;
57             }
58             //將網路流中的圖片數據段順序寫入本地
59             fs.Write(buffer,0,bufferlength);
60             //再次非同步讀取
61             _ns.BeginRead(buffer, 0, bufferlength, ReadAsyncCallBack, null);
62         }
63     }

客戶端代碼:

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             SendImageToServer(@"E:\111.jpg");
 6         }
 7 
 8         static void SendImageToServer(string imgUrl)
 9         {
10             if (!File.Exists(imgUrl))
11             {
12                 return;
13             }
14             //創建一個文件流打開圖片
15             FileStream fs = File.Open(imgUrl, FileMode.Open);
16             //聲明一個byte數組接收圖片byte信息
17             byte[] fileBytes = new byte[fs.Length];
18             using (fs)
19             {
20                 //將圖片byte信息讀入byte數組中
21                 fs.Read(fileBytes, 0, fileBytes.Length);
22             }
23             //找到伺服器的IP地址
24             IPAddress address = IPAddress.Parse("127.0.0.1");
25             //將建TcpClient對象實現與伺服器的連接
26             TcpClient client = new TcpClient();
27             //連接伺服器
28             client.Connect(address, 9090);
29             using (client)
30             {
31                 //連接完伺服器後便在客戶端和伺服器之間產生一個流的通道
32                 NetworkStream ns = client.GetStream();
33                 using (ns)
34                 {
35                     //通過此通道將圖片數據吸入網路流,傳向伺服器接收
36                     ns.Write(fileBytes, 0, fileBytes.Length);
37                 }
38             }
39         }
40     }

這樣就可以通過socket把圖片傳遞過去了。

好了,關於NetworkStream的相關知識就介紹到這裡了~


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

-Advertisement-
Play Games
更多相關文章
  • 數據結構 數據結構(演算法)的介紹 數據結構的介紹 1) 數據結構是一門研究演算法的學科,只從有了編程語言也就有了數據結構.學好數據結構可以編寫 出更加漂亮,更加有效率的代碼。 2) 要學習好數據結構就要多多考慮如何將生活中遇到的問題,用程式去實現解決. 3) 程式 = 數據結構 + 演算法 20.2 數 ...
  • 一、前言 在概念上, click 把命令行分為 3 個組成:參數、選項和命令。 參數 就是跟在命令後的除選項外的內容,比如 git add a.txt 中的 a.txt 就是表示文件路徑的參數 選項 就是以 或 開頭的參數,比如 f、 file 命令 就是命令行的初衷了,比如 git 就是命令,而 ...
  • 本筆記摘抄自:https://www.cnblogs.com/zhili/archive/2012/07/18/Thread.html,記錄一下學習過程以備後續查用。 一、線程的介紹 進程(Process)是應用程式的實例要使用的資源的一個集合,每個應用程式都在各自的進程中運行來確保應用程式不受其他 ...
  • using System.Reflection; static void ShowEnvironmentInfoDemo() { Type type = typeof(Environment); PropertyInfo[] pis = type.GetProperties(); if (pis !... ...
  • private void ClickCmdExecuted(object obj) { ContentOb = new ObservableCollection<string>(); Task.Run(() => { while (!cts.IsCancellationRequested) { Co ...
  • 修改屏幕DPI,會觸發控制項的Unloaded/Loaded 現象/重現案例 對Unloaded/Loaded的印象: FrameworkElement, 第一次載入顯示時,會觸發Loaded。元素被釋放時,會觸發Unloaded。視窗Show/Close時,視覺樹變化都會觸發載入事件 MenuIte ...
  • 最近做項目的時候,需要對接廠商提供的 IP 攝像頭。但是他們只提供了 C++ 的 SDK,沒辦法,只能開始擼 C 的 SDK Helper 類。本篇文章主要記錄了對接 C++ DLL 需要註意的幾個地方,以及常見類型的轉換。 要對接 C++ 的 DLL,首先得知道如何引用 DLL 內的方法。在 C ...
  • 現象: 項目中導入Ocelot後,swagger頁面無法正常顯示,查看異常發現 Ocelot.Raft.RaftController 中的 Action 配置不完全,swagger掃描時不能正確生成 swagger.json 解決方法: 在掃描中隱藏Ocelot的controller,避免被swag ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...