【光學相機】關於網路通信的方法及函數

来源:http://www.cnblogs.com/liyulongBlog/archive/2017/12/07/7998153.html
-Advertisement-
Play Games

一.TcpClient與TcpServe。 首先我們需要知道伺服器的IP地址,在伺服器端建立監聽,當監聽到客戶端的連接請求後,連接到客戶端。 而客戶端則需要連接到指定的IP伺服器地址,建立網路流,則可以實現通信。 接下來給出一個伺服器端與客戶端的實例: 伺服器端: 此時伺服器端應用的是Socket類 ...


一.TcpClient與TcpServe。

首先我們需要知道伺服器的IP地址,在伺服器端建立監聽,當監聽到客戶端的連接請求後,連接到客戶端。

而客戶端則需要連接到指定的IP伺服器地址,建立網路流,則可以實現通信。

接下來給出一個伺服器端與客戶端的實例:

伺服器端:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;

namespace fuwuqi
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                IPAddress Ip = IPAddress.Parse("127.0.0.1");
                //IPAddress提供網際協議地址的類,Parse將IP地址字元串轉換為IPAddress的實例   
                TcpListener TcpList = new TcpListener(Ip, 8888);
                //TcpListener網路偵聽類,從TCP網路客戶端偵聽連接,TcpListener (參數1,參數2),參數1表示本地IP地址,參數2表示用來偵聽傳入的埠連接   
                TcpList.Start();
                //啟動對掛起連接數的傳入鏈接請求的偵聽   
                Console.WriteLine("Server start!");
                Console.WriteLine("Ip address:" +TcpList.LocalEndpoint);
                //LocalEndpoint獲取服務端(即本地)地址與埠等信息   
                Console.WriteLine("Wait");
                Socket Soc = TcpList.AcceptSocket();//相當於啟動客戶端後,Socket被掛起
                //AcceptSocket表示接受掛起的連接請求,Socket為套接字介面的類   
                Console.WriteLine("Received Connection:" + Soc.RemoteEndPoint);
                //RemoteEndPoint獲取客戶端地址與埠等信息   
                byte[] b = new byte[100];
                int k = Soc.Receive(b);
                //Soc.Receive(b)從socket接收數據,將數據存入接收緩衝區列表中,k的值為該數據的長度   
                Console.WriteLine("Received data from client:");
                for (int i = 0; i < k; i++)
                    Console.Write(Convert.ToChar(b[i]));
                //Convert.ToChar(b[i])將數組b轉換基本數據類型為char的類型並輸出   
                ASCIIEncoding AS = new ASCIIEncoding();
                //ASCIIEncoding表示Unicode字元的ASCII字元編碼類   
                Soc.Send(AS.GetBytes("Received data!"));
                //Soc.Send向客戶端發送數據,AS.GetBytes()獲得括弧中字元串的bytes值   
                Soc.Close();
                //關閉連接並釋放所有關聯的資源   
                TcpList.Stop();
                //關閉偵聽   
                Console.ReadLine();
                //等待輸入,起到暫停的作用   
            }
            catch (Exception e)
            {
                Console.WriteLine("Error!" + e.StackTrace);
                //獲取當前異常發生時調用堆棧上的幀的字元串   
            }
        }
    }
}

此時伺服器端應用的是Socket類發送數據流,Socket類用於客戶端和伺服器都可,其發送機制是以一種包的形式發送,在做項目時,發現Socket接收到的數據包與發送到的數據包長度不一定吻合,有阻塞,所以使用Socket數據包發送時,接收和發送的數據組要指定長度,太長也會丟數。

客戶端:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Net.Sockets;
namespace kehuduan
{
    class Program
    {
        
            static void Main(string[] args)  
        {
                try
                {
                    TcpClient TcpClient = new TcpClient();
                    //TcpClient為TCP網路服務提供客戶端連接的類   
                    TcpClient.Connect("127.0.0.1", 8888);
                    //Connect方法使用指定的IP地址和埠號將客戶端連接到遠程TCP主機   
                    Console.WriteLine("Connect Complete");

                    Console.WriteLine("Input string:");
                    String str = Console.ReadLine();
                    //定義字元串str變數,保存輸入的字元   
                    Stream stm = TcpClient.GetStream();
                    //定義數據流,用於發送和接收數據   
                    ASCIIEncoding AS = new ASCIIEncoding();
                    byte[] b = AS.GetBytes(str);
                    //將字元串轉換為byte類型   
                    stm.Write(b, 0, b.Length);
                    //Write(參數1,參數2,參數3)表示向服務端發送字元串,參數1指將此數組複製到當前流,參數2指從零開始的位元組偏移量,參數3指要寫入當前流的位元組數(即字元串長度)   
                    Console.WriteLine("Send Complete");
                    byte[] bb = new byte[100];
                    int k = stm.Read(bb, 0, 100);
                    //stm.Read在當前流中讀入服務端發來的響應信息,其參數與Write方法參數一致,k值為讀入字元串的長度   
                    for (int i = 0; i < k; i++)
                        Console.Write(Convert.ToChar(bb[i]));
                    TcpClient.Close();
                    //釋放TcpClient實例,並不關閉基礎連接   
                    Console.ReadLine();
                }
                catch (Exception e)
                {
                    Console.WriteLine("Error!" + e.StackTrace);
                }
            }
        }
    }

上面展示了客戶端與伺服器端的簡單通信。作為例子程式學習,接下來對自己做的項目中連接攝像頭伺服器做一個記錄。

首先,把攝像頭作為伺服器端,定義客戶端:

   TcpClient client = new TcpClient("IP",8080);

獲取網路流:

  NetworkStream networkstream = client.GetStream();//獲取網路流

此時可以建立與伺服器端的網路流連接,如果需要從網路流中讀取數據或者寫入數據,使用了BinaryReader/BinaryWriter或者StreamReader/StreamWriter,實例化後,就可實現對流的讀寫

BinaryReaderbr = new BinaryReader(networkstream);
BinaryWriter bw = new BinaryWriter(networkstream);
我對這兩個的理解是StreamReder讀取函數ReadToEnd,ReadLine等,讀取出來是字元串類型。而BinaryReader可以按位元組讀取。根據需求選取。

(筆記StreamReader的方法: sr.BaseStream.Seek(0, SeekOrigin.Begin);//從流中當前開始的位置(SeekOrigin.begin)偏移0位讀取)

如果需要對伺服器發送數據直接寫入流,使用Write等函數就可以了。

 

這裡對自己找的資料也做一個總結。

MemoryStream類:

Memmory類相當於一個緩存流,首先需要對這個流開闢一個空間,然後將數據放入流中對其進行操作。該流的優勢在於可以將數據先放入流中,然後使用指針對流中的任一個位元組進行操作。

學習例子:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;


namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            //屬性測試
            MemoryStream ms = new MemoryStream();
            Console.WriteLine(ms.CanRead);      //True  記憶體流可讀
            Console.WriteLine(ms.CanSeek);      //True  記憶體流支持查找,指針移來移去的查找
            Console.WriteLine(ms.CanTimeout);   //False 記憶體流不支持超時
            Console.WriteLine(ms.CanWrite);     //True  記憶體流可寫

            Console.WriteLine(ms.Capacity);     //0     分配給該流的位元組數
            byte[] bytes = Encoding.UTF8.GetBytes("abcdedcba");//字元轉為ASCII
            ms.Write(bytes, 0, bytes.Length);   //已將一段文本寫入記憶體
            int l = bytes.Length;
            Console.WriteLine(ms.Capacity);     //256   再次讀取為文本流分配的位元組數已經變成了256,看來記憶體流是根據需要的多少來分配的
            Console.WriteLine(ms.Length);       //9    這個是流長度,通常與英文的字元數一樣,真正占用的位元組數。

            Console.WriteLine(ms.Position);     //9    流當前的位置,該屬性可讀可設置

            //Console.WriteLine(ms.ReadTimeout);    由於流不支持超時,此屬性如果讀取或者設置的話會報錯
            //Console.WriteLine(ms.WriteTimeout);   由於流不支持超時,此屬性如果讀取或者設置的話會報錯

            //方法測試
            
            byte[] byte1 = ms.GetBuffer();          //返回無符號位元組數組 差點被忽悠了,無符號位元組數組 其實就是byte(0~255),有符號位元組sbyte(-128~127)
            string str1 = Encoding.UTF8.GetString(byte1);
            Console.WriteLine(str1);    //輸出    abcdedcba
            long p = ms.Position;//指針當前位置
            ms.Position = 0;
            ms.Seek(0, SeekOrigin.Current);    //設置當前流正在讀取的位置 為開始位置即從0開始
            //從記憶體中讀取一個位元組
            int i = ms.ReadByte();
            Console.WriteLine(i);                   //輸出99
            byte[] bytes3 = ms.ToArray();
            foreach (byte b in bytes3)
            {
                Console.Write(b + "-");//用於對比   輸出 97-98-99-100-101-100-99-98-97-   可以看到    0,1,2第二位剛好是99
            }

            MemoryStream ms2 = new MemoryStream();
            byte[] bytes6 = Encoding.UTF8.GetBytes("abcde");
            ms2.Write(bytes6, 0, bytes6.Length);
            Console.WriteLine(ms2.Position);    //輸出5 寫完之後流的位置就到了最後,因此想用read讀取必須加下麵這一行代碼。 

            //ms2.Seek(0, SeekOrigin.Begin);    //想要用Read方法讀取完整的流,必須設置當前位置,Read是從Position的位置開始讀。
            ms2.Position = 0;                   //Read是從當前位置開始讀,這行代碼和上面一行意義一樣。
            byte[] byteArray = new byte[5] { 0, 0,0, 0, 0 }; //數組附初值全部是0
            ms2.Read(byteArray, 2, 1);   //讀取一個位元組,byteArray的第一個元素中,(註意從0開始)讀取數據流里第二個位子開始讀取一個
            Console.WriteLine(Encoding.UTF8.GetString(byteArray)); //nnann
            ms2.Read(byteArray, 2, 2);
            Console.WriteLine(Encoding.UTF8.GetString(byteArray)); //nnabn    //當超出接收數組總長度的時候,後面的元素會被移開


            //設置當前流的長度
            Console.WriteLine(ms.Length);   //輸出9   當前流的長度是9
            ms.SetLength(20);
            Console.WriteLine(ms.Length);   //輸出20
            foreach (byte b in ms.ToArray())    //將流的內容也就是記憶體中的內容轉換位元組數組
            {
                Console.Write(b + "-");     //輸出 97-98-99-100-101-100-99-98-97-0-0-0-0-0-0-0-0-0 由於設置了長度,因此空的自動補0
            }
            Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));   //輸出    abcdedcba   雖然長度變長了,但是沒影響讀取數據

            MemoryStream ms1 = new MemoryStream();
            byte[] bytes4 = ms1.ToArray();
            Console.WriteLine("此記憶體流並沒有寫入數據(Write)" + Encoding.UTF8.GetString(bytes4));//輸出    此記憶體流並沒有寫入數據(Write)  因為記憶體為空


            //下麵來一個指定位置的寫入
            MemoryStream ms3 = new MemoryStream();
            byte[] bytesArr = Encoding.ASCII.GetBytes("abcdefg");
            ms3.Write(bytesArr, 0, bytesArr.Length);
            ms3.Position = 2;
            ms3.WriteByte(97);  //97代表的是a   這段代碼的意思是,將原先第二個的c替換為a
            string str = Encoding.ASCII.GetString(ms3.ToArray());
            Console.WriteLine(str); //輸出 abacdefg

            byte[] byteArr1 = Encoding.ASCII.GetBytes("kk");
            ms3.Position = 4;
            ms3.Write(byteArr1, 0, byteArr1.Length);
            Console.WriteLine(Encoding.UTF8.GetString(ms3.ToArray()));  //abadkkg   //從第4位替換掉了兩個位元組為KK

            Console.ReadKey();
        }
    }
}

 


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

-Advertisement-
Play Games
更多相關文章
  • NPOI版本:2.2.1.0 最近公司有這樣的需求: 統計每個部門下麵,多個費用使用情況。部門存在多級,但統計時,只需統計到2級,2級以下的,歸到第2級的部門下。並且要求,第2級部門有個小計,第1級部門需要有個合計。最後,還需提供總計。 本來對NPOI研究的還不夠深入的,以前都是直接通過別人提供的代 ...
  • 很多人一開始學習.net 第一天必定是安裝Visual studio 或者很多關於C#學習的書上第一章節必定是告訴你要你下載一個vs 其實沒有vs未必就不能開發了,只是可能說vs給我的開髮帶來了很多的便捷,但是作為初學者一開始就用它,可能會導致你忽略 了很多原理性的東西 , 一般在windowxp以 ...
  • 1 //==>自建線程 2 new Thread(() => 3 { 4 //線程任務 5 Console.WriteLine(Thread.CurrentThread.ManagedThreadId); 6 }).Start(); 7 8 9 //==>線程池管理線程(不知道線程任務用時,不能控制... ...
  • 數據表格能夠清晰的呈現數據信息,但是我們對於一些繁雜多變的數據想要很直觀的看到數據變化走勢或者數據的占比時,數據圖表會更具代表性,並且在呈現數據信息上也更形象,也能獲取更多純數字信息所不能直接展現的信息。在下麵的代碼中,將向您展示如何通過使用免費的Free Spire XLS for .NET組件來 ...
  • 1.父類必須包含構造函數麽? 父類必須要有一個構造函數,有參無參都可以。 構造函數是對象的基本,沒有構造函數就沒有對象,若父類中顯示的有參數的構造函數,在子類繼承就必須寫一個構造函數來調用父類的構造函數。 如果父類中有沒有參數的構造函數,在子類中可以不顯示的寫父類的構造函數,系統會自動調用沒有參數的 ...
  • 前段時間,Insus.NET有實現一組字元串在輸出時,靠左或靠右對齊。《輸出的字元靠右對齊》http://www.cnblogs.com/insus/p/7953304.html 現在Insus.NET參考此方法,實一張塔松葉,實現之前,先練習一下,輸出半張: public void WriteTr ...
  • 當Web Api 2.0使用OAuth2授權時,如何在Swagger中添加Authorization請求頭? Swagger說明文檔支持手動調用Api, 但是當Api使用OAuth2授權時,由於沒有地方可以輸入授權Token, 導致響應結果一直是401沒有授權。 解決方案: 在Swagger配置文件 ...
  • Ticks是一個周期,存儲的是一百納秒,換算為秒,一千萬分之一秒。我們需要計算2個時間之間,經過多少Ticks,可以使用下麵的方法來實現,使用2個時間相減。得到結果為正數,是使用較晚的時間減去較早的時間。反之為負數,即是使用較早的時間減去較晚的時間。創建一個對象: class Ag { privat ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...