C#實現完整的防盜自製監控系統

来源:https://www.cnblogs.com/langda/archive/2018/12/20/10152871.html
-Advertisement-
Play Games

在您的手機中通知您家中的入侵者,並拍攝他們的照片 介紹 在本文中,我將展示一些DIY東西​​,用於安裝監控系統,檢測家中的入侵者,拍攝照片並通過手機通知您,必要時可以打電話給警察並提供照片以便快速識別劫匪,並提高你恢復所有被盜事物的機會。 當然,除了這個軟體,你必須提供一些硬體,但我已經在我家使用相 ...


在您的手機中通知您家中的入侵者,並拍攝他們的照片

介紹

在本文中,我將展示一些DIY東西​​,用於安裝監控系統,檢測家中的入侵者,拍攝照片並通過手機通知您,必要時可以打電話給警察並提供照片以便快速識別劫匪,並提高你恢復所有被盜事物的機會。

當然,除了這個軟體,你必須提供一些硬體,但我已經在我家使用相對便宜的材料建造了這個系統,如果我們除了相機,這是安裝中最昂貴的部分。但你可以用相機做很多事情,所以它可以是一個好的和有趣的投資。

基本上,這是系統架構,包含所有參與元素:

雖然在模式中我已經代表了一些具體的子系統,但實際上我已經設計瞭解決方案,以便通過實現公共介面並使用依賴註入將它們與應用程式鏈接,可以獨立開發所有這些元素。不同的子系統或協議如下:

  • 攝像機協議:定義與攝像機的通信。
  • 存儲協議:定義文件傳輸,圖像和控制命令/響應。
  • 觸發協議:啟動監控系統。
  • 警報協議:將事件遠程傳達給用戶。

該解決方案使用Visual Studio 2015和4.5版的.Net Framework實現。

你可以在我的博客中找到這篇文章的更長版本網站源碼,這裡有西班牙文版本。由於此站點的文件大小限製為10MB,我不得不刪除源代碼中的大量文件,所有NuGet包,obj目錄和所有二進位文件。雖然您可以從Visual Studio還原包,但您可能無法重新編譯代碼。在這種情況下,您可以從我的網站,在上一個鏈接中下載項目的完整文件集。

硬體

讓我們回顧一下我用來構建系統的硬體。由於應用程式可以通過多種方式進行擴展,因此您可以使用自己的不同硬體選擇來安裝它。

首先是相機。我有兩個IP攝像頭,每個都有不同的協議。更便宜的是一個概念性的wifi攝像頭,價格約50€和協議NetWave cgi。另一種是專業的,具有高性能,但也是非常高的價格。這是一款採用VAPIX cgi協議的Axis相機。

為了撥打行動電話,我買了一個簡單的USB AT數據機,價格約為17歐元:

當然,作為觸發器,我使用的是Arduino板(約20歐元),存在探測器開關(約10歐元)和繼電器。由於存在開關適用於220V,因此將其直接連接到Arduino板是一個壞主意。因此,我已將探測器連接到12V電源,並將繼電器的電源連接到另一個開關,該電源關閉5V Arduino電源和輸入引腳之間的電路。這完全隔離了220V主電源的Arduino板(以及電腦)。

你可以輕鬆地建立一個繼電器電路。只需將12個電源連接到繼電器卷軸,將二極體從地線連接到12V電線,然後從Arduino側使用輸入引腳(PI)作為觸發引腳,輸出引腳(PO)用力電路開路時輸入引腳為0V,5V電源信號激活輸入引腳:

這是Arduino代碼,我使用引腳28作為輸入,24使用輸出,因為在Arduino Mega板中它們靠近5V引腳,但是你可以使用你想要的,當然。

int pin1 = 28;
int pin0 = 24;
void setup() {
// Initialize pins
    pinMode(pin0, OUTPUT); 
    digitalWrite(pin0, LOW);
    pinMode(pin1, INPUT);
    digitalWrite(pin1, LOW);
    Serial.begin(9600);
}
void loop() {
    int val = digitalRead(pin1);
    if (val == HIGH) {
        Serial.write(1);
    }
    delay(1000);
}

  

最後,雖然這不是真正的硬體,但我會提到我使用過的存儲協議。我選擇Dropbox作為將照片上傳到雲端的最簡單,最便宜的方式,我還使用此媒體將移動客戶端與控制中心進行通信,使用帶有JSON格式數據的文本文件。

控制中心

在ThiefWatcher項目中,實現了中央控制應用程式。它是一個桌面MDI Windows應用程式,基本上有兩種不同的視窗類型。其中一個是控制面板,您可以在其中設置所有協議,而不是攝像機:

頂部窗格用於觸發器協議。在這裡,您可以選擇要使用的協議,提供具有相應設置的連接字元串(可以從協議到另一個不同),系統必須啟動監視模式的開始日期/時間(如果您不提供,系統啟動(中間),停止監視的結束日期/時間,您可以配置檢測到入侵者時拍攝的照片數量和照片之間的秒數(整數)。

此窗格下方是通知(警報)協議。在下拉列表右側選擇協議,您有一個測試按鈕,允許您測試此協議,而無需進行任何模擬。您還必須提供帶參數設置的字元串連接,併在協議允許數據傳輸的情況下提供可選消息。

底部窗格用於存儲協議。您有一個連接字元串來設置參數(如果有)和一個用於存儲數據的容器名稱,可以是本地文件夾,FTP文件夾,Azure blob容器名稱等。

命令按鈕從左到右依次為Start Simulacrum,它啟動或停止系統,就像檢測到入侵者一樣,因此您可以測試攝像機和存儲協議以及與客戶端的通信。在此模式下,不考慮開始和結束日期。接下來,“ 開始”按鈕啟動或停止實際監控模式。相機形式中沒有顯示圖像(假設沒有人在場)。最後,“ 保存”按鈕會在配置文件中寫入更改。

在代碼使用部分,我將評論我已實現的所有協議的連接字元串的參數。

關於攝像機協議,每個攝像機的配置都在攝像機視窗中執行,您可以使用File / New Camera ...菜單選項顯示攝像機視窗。首先,您必須為要添加的攝像機選擇正確的攝像機協議,然後,您必須提供連接數據,攝像機URL,用戶名和密碼。然後,你可以看到這樣一個視窗:

工具欄左側的第一個按鈕用於更改訪問設置,第二個按鈕用於顯示相機設置對話框,該對話框在相應的協議中實現。然後,您有一個啟動按鈕和其他停止相機的按鈕,因此您可以在配置相機時觀看圖像。攝像機ID必須是唯一的並且是必需的,因為您將使用此ID從客戶端選擇攝像機。最後兩個按鈕用於將攝像機保存在配置文件中或將其刪除。

所有這些設置都存儲在應用程式  App.config文件中。connectionStrings部分中的連接字元串,appSettings部分中的其他協議設置。還有兩個自定義部分用於存儲協議列表以及不同的攝像機及其設置。

該cameraSection islike這樣的:

<camerasSection>
    <cameras>
        <cameraData id="CAMNW"
            protocolName="NetWave IP camera"
            connectionStringName="CAMNW" />
        <cameraData id="VAPIX"
            protocolName="VAPIX IP Camera"
            connectionStringName="VAPIX" />
    </cameras>
</camerasSection>

  

每個照相機是一個cameraData元件,具有一個ID屬性,protocolName與相應協議的名稱屬性,和一個的connectionStringName用於連接數據屬性:URL,userName的和密碼,存儲在一個連接字元串中的ConnectionStrings部分。

還有一個protocolsSection,包含已安裝協議的列表:

<protocolsSection>
    <protocols>
        <protocolData name="Arduino Simple Trigger"
            class="trigger"
            type="ArduinoSimpleTriggerProtocol.ArduinoTrigger, ArduinoSimpleTriggerProtocol, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
        <protocolData name="Lync Notifications"
            class="alarm"
            type="LyncProtocol.LyncAlarmChannel, LyncProtocol, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
        <protocolData name="AT Modem Notifications"
            class="alarm"
            type="ATModemProtocol.ATModemAlarmChannel, ATModemProtocol, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
        <protocolData name="Azure Blob Storage"
            class="storage"
            type="AzureBlobProtocol.AzureBlobManager, AzureBlobProtocol, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
        <protocolData name="NetWave IP camera"
            class="camera"
            type="NetWaveProtocol.NetWaveCamera, NetWaveProtocol, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
        <protocolData name="VAPIX IP Camera"
            class="camera"
            type="VAPIXProtocol.VAPIXCamera, VAPIXProtocol, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
        <protocolData name="DropBox Storage"
            class="storage"
            type="DropBoxProtocol.DropBoxStorage, DropBoxProtocol, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
    </protocols>
</protocolsSection>

  

每個協議有一個名字,一類,以確定它們的用法(觸發,報警,存儲或相機)和類型與所述完整的類型,其實現協議的類。

您可以使用File / Install Protocol / s ...菜單選項向此部分添加新協議,選擇具有協議或協議實現的類庫。

客戶

無論您身在何處,應用程式都必須通知您可能的入侵,因此我將客戶端實現為移動應用程式。幾乎所有平臺快速擁有應用程式版本的最簡單方法是使用Xamarin來執行此操作,因此這是我選擇的方法。

該TWClientApp PCL(攜帶型類庫)項目包含在客戶端幾乎所有的代碼。在不同平臺的具體項目中,只有代碼保存文件,將攝像頭拍攝的照片保存在手機記憶體中,以便您儘快將其提供給警方。

這是我的第一個移動App項目,所以它不是很複雜。這裡我沒有使用依賴註入。相反,我只實現了Dropbox存儲協議,因此,如果要使用另一個協議,則必須更改PCL庫中的代碼。此協議的優點是您可以使用Dropbox實際客戶端獲取照片,而無需使用ThiefWatcher客戶端(儘管您失去了應用程式控制功能)。

啟動客戶端應用程式時,必須按“ 連接”按鈕才能向主應用程式發送標識消息:

然後,將相機列表發送到客戶端。您可以按相應的按鈕選擇其中一個:

您可以觀看相機的當前圖像。通常,您不能等待真正的視頻流,因為上傳每個圖像可能會非常慢。中央控制實時獲取幀,但Dropbox每上傳花費最多兩秒鐘。

您可以使用按鈕啟動/停止相機,拍照或結束鬧鐘模式(在結束鬧鐘模式之前無需停止相機)。

照片顯示在底部的列表中,您可以將其保存到手機或刪除它們。

我無法測試iOS版本,因為我沒有MAC,但Windows Phone和Android Apps工作正常。

使用代碼

不同的協議介面在WatcherCommons項目的Interfaces名稱空間中定義。攝像機協議是IWatcherCamera,定義如下:

public class FrameEventArgs : EventArgs
{
    public FrameEventArgs(Bitmap bmp)
    {
        Image = bmp;
    }
    public Bitmap Image { get; private set; }
}
public delegate void NewFrameEventHandler(object sender, FrameEventArgs e);
public interface IWatcherCamera
{
    event NewFrameEventHandler OnNewFrame;
    Size FrameSize { get; }
    string ConnectionString { get; set; }
    string UserName { get; set; }
    string Password { get; set; }
    string Uri { get; set; }
    int MaxFPS { get; set; }
    bool Status { get; }
    ICameraSetupManager SetupManager { get; }
    void Initialize();
    void ShowCameraConfiguration(Form parent);
    void Start();
    void Close();
}

  

  • OnNewFrame:當圖像準備好發送到應用程式時觸發事件處理程式。圖像在FrameEventArgs參數的Image屬性中作為Bitmap傳遞。
  • FrameSize:攝像機圖像的當前寬度和高度。
  • ConnectionString:用分號分隔的字元串,用於定義攝像機訪問參數。在我實現的協議中,參數是url,userName和password,如下所示:url = http://192.168.1.20; userName = root; password = root。
  • UserName,Password和Uri:與連接字元串中的相同。
  • MaxFps:設置捕獲率。
  • 狀態:如果攝像機正在運行,則為true。
  • SetupManager:與攝像機設置對話框的界面。用於在用戶更改攝像機圖像大小時在應用程式中觸發事件,以便可以正確調整攝像機表單的大小。
  • 初始化:根據需要重置內部狀態。
  • ShowCameraConfiguration:顯示攝像機配置對話框。它必須不是模態的,因此如果相機正在顯示圖像,您可以觀察更改。
  • 開始:開始圖像捕獲。這是在一個單獨的線程中執行的,您必須在新幀事件中與相機交互時將其考慮在內。
  • 停止:停止捕獲。

該NetWave協議在實施NetWaveProtocol項目和VAPIX在協議VAPIXProtocol項目。

觸發器協議ITrigger如下:

 public interface ITrigger
{
    event EventHandler OnTriggerFired;
    string ConnectionString { get; set; }
    void Initialize();
    void Start();
    void Stop();
}

  

  • OnTriggerFired:在檢測到觸發條件時觸發。
  • ConnectionString:帶有配置參數的字元串。在我已經實現的協議中,在ArduinoSimpleTriggerProtocol項目中,它們是埠和波特率,如下所示:port = COM4; baudrate = 9600。請記住在Arduino代碼中設置相同的波特率。
  • 初始化:根據需要重置intarnal狀態。
  • 開始:開始偵聽觸發條件。這是在一個單獨的線程中完成的。
  • 停止:停止聽。

通知協議IAlarmChannel也很簡單:

public interface IAlarmChannel
{
    string ConnectionString { get; set; }
    string MessageText { get; set; }
    void Initialice();
    void SendAlarm();
} 

  

  • ConnectionString:帶有配置參數的字元串。
  • MessageText:如果協議允許,則發送消息。
  • 初始化:重置內部狀態。
  • SendAlarm:向客戶端發送通知。

我實現的協議是ATModemProtocol項目,它使用AT數據機撥打一個或多個電話號碼,並具有以下配置參數:

  • port:連接數據機的COM埠。
  • 波特率:設置埠波特率。
  • initdelay:撥號前等待的延遲時間(以毫秒為單位)。
  • number:逗號分隔的電話號碼列表。
  • ringduration:掛機前的時間,以毫秒為單位。

另一個協議使用Skype或Lync通知用戶。它在LyncProtocol項目中實現。連接字元串是以分號分隔的Skype或Lync用戶地址列表。您必須在主電腦和客戶端上安裝Lync客戶端。

後者是存儲協議,此協議使用的數據在WatcherCommons類庫的Data命名空間中定義。有兩個不同的類,ControlCommand用於攝像頭命令:

[DataContract]
public class ControlCommand
{
    public const int cmdGetCameraList = 1;
    public const int cmdStopAlarm = 2;
    public ControlCommand()
    {
    }
    public static ControlCommand FromJSON(Stream s)
    {
        s.Position = 0;
        StreamReader rdr = new StreamReader(s);
        string str = rdr.ReadToEnd();
        return JsonConvert.DeserializeObject<ControlCommand>(str);
    }
    public static void ToJSON(Stream s, ControlCommand cc)
    {
        s.Position = 0;
        string js = JsonConvert.SerializeObject(cc);
        StreamWriter wr = new StreamWriter(s);
        wr.Write(js);
        wr.Flush();
    }
    [DataMember]
    public int Command { get; set; }
    [DataMember]
    public string ClientID { get; set; }
}

  

命令以JSON格式發送和接收。在Command成員中傳遞了兩個不同的commnand,一個用於嚮應用程式註冊並獲取攝像機列表,另一個用於停止警報並將應用程式重置為監視模式。

該客戶端ID構件唯一地標識每個客戶端。

CameraInfo也是以JSON格式交換有關攝像機的請求和響應:

[DataContract]
public class CameraInfo
{
    public CameraInfo()
    {
    }
    public static List<CameraInfo> FromJSON(Stream s)
    {
        s.Position = 0;
        StreamReader rdr = new StreamReader(s);
        return JsonConvert.DeserializeObject<List<CameraInfo>>(rdr.ReadToEnd());
    }
    public static void ToJSON(Stream s, List<CameraInfo> ci)
    {
        s.Position = 0;
        string js = JsonConvert.SerializeObject(ci);
        StreamWriter wr = new StreamWriter(s);
        wr.Write(js);
        wr.Flush();
    }
    [DataMember]
    public string ID { get; set; }
    [DataMember]
    public bool Active { get; set; }
    [DataMember]
    public bool Photo { get; set; }
    [DataMember]
    public int Width { get; set; }
    [DataMember]
    public int Height { get; set; }
    [DataMember]
    public string ClientID { get; set; }
} 

  

  • ID:攝像機標識符。
  • 活動:相機狀態。
  • 照片:用於要求相機拍照。
  • 寬度和高度:相機圖像尺寸。
  • ClientID:客戶端唯一標識符。

當您請求攝像機列表時,您會收到一個帶有一系列CameraInfo對象的響應,每個攝像機對應一個。

實現協議的介面是IStorageManager:

public interface IStorageManager
{
    string ConnsecionString { get; set; }
    string ContainerPath { get; set; }
    void UploadFile(string filename, Stream s);
    void DownloadFile(string filename, Stream s);
    void DeleteFile(string filename);
    bool ExistsFile(string filename);
    IEnumerable<string> ListFiles(string model);
    IEnumerable<ControlCommand> GetCommands();
    IEnumerable<List<CameraInfo>> GetRequests();
    void SendResponse(List<CameraInfo> resp);
} 

  

  • ConnectionString:帶有配置參數的字元串。
  • ContainerPath:標識文件夾,blob容器名稱等。
  • UploadFile:發送Stream對象中提供的文件。
  • DownloadFile:在提供的Stream對象中獲取文件。
  • DeleteFile:刪除文件。
  • ExistsFile:測試文件是否存在。
  • ListFiles:枚舉文件夾中的文件,其名稱的開頭必須與模型參數匹配  。
  • GetCommands:枚舉客戶端發送的命令。
  • GetRequests:枚舉客戶端發送的攝像頭請求。
  • SendResponse:發送命令或攝像機請求的響應。

我已經實現了兩個存儲協議。該DropBoxProtocol項目實施與使用的協議的Dropbox。在伺服器端,這隻是讀取和寫入Dropbox文件夾的文件。不需要連接字元串,因為文件夾是單獨配置的。

在客戶端中,這是實現的協議。它略有不同,界面在TWClientApp項目中定義:

public interface IStorageManager
{
    Task DownloadFile(string filename, Stream s);
    Task DeleteFile(string filename);
    Task<bool> ExistsFile(string filename);
    Task<List<string>> ListFiles(string model);
    Task SendCommand(ControlCommand cmd);
    Task SendRequest(List<CameraInfo> req);
    Task<List<CameraInfo>> GetResponse(string id);
} 

  

它是一個非同步介面,成員數少於伺服器端。實現並不像伺服器那麼容易; 我們必須使用Dropbox API與之交互。實現在DropBoxStorage類中,並且在_accessKey常量中,您必須將安全密鑰設置為成功建立連接(在第一次編譯代碼之前不要忘記這樣做,因為沒有預設值)。

private const string _accessKey = ""; 

客戶端App的幾乎所有代碼都在TWClientApp項目中,在CameraPage類中。數據的交換協議是通過文件,每個文件都有一個特殊的名稱來識別它。這些是不同的文件名模式:

  • 攝像機只寫一個幀文件,當客戶端讀取幀時,它刪除文件,伺服器可以寫另一個。該文件是jpg圖片,名稱為<CAMERA ID> _FRAME_ <CLIENT ID> .jpg。
  • 照片的名稱相似,可能有多張照片。名稱模式為:<CAMERA ID> _PHOTO_yyyyMMddHHmmss.jpg。
  • 客戶端可以以JSON文本格式和名稱cmd_ <CLIENT ID> .json將命令一次發送到伺服器。
  • 當伺服器獲取命令文件時,它會刪除該文件,因此客戶端可以發送另一個命令,並執行該命令。然後,它編寫一個名為resp_ <CLIENT ID> .json的響應文件。
  • 最後,客戶端可以發送相機請求,例如拍攝照片,或以JSON格式在名為req_ <CLIENT ID> .json的文件中啟動或停止相機。伺服器讀取文件,刪除它,並將請求傳遞給攝像機進行處理,然後,伺服器寫入響應文件,就像命令一樣,具有攝像機狀態。

該NetWave相機協議配置對話框非常簡單,你可以閱讀更多關於此協議中我的博客。

至於VAPIX協議,它更複雜,因為它是專業相機的協議。我沒有使用包含大量控制項的複雜對話框,而是實現了一個包含所有配置參數的樹視圖(它們是很多配置參數),您可以在其中選擇每個參數並更改值。您也可以在我的博客中閱讀更多相關信息。

這就是全部,享受解決方案,並感謝閱讀!


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

-Advertisement-
Play Games
更多相關文章
  • 例題import lxml.html test_data = """ <div> <ul> <li class="item-0"><a href="link1.html" id="places_neighbours__row">9,596,960first item</a></li> <li cla ...
  • sql註入後可以通過該資料庫獲取所有表的欄位信息 1. COLLATIONS表 提供有關每個字元集的排序規則的信息。 COLLATIONS表包含以下列: COLLATION_NAME 排序規則名稱。 CHARACTER_SET_NAME 與排序規則關聯的字元集的名稱。 ID 排序規則ID。 IS_D... ...
  • 在理解有向圖和強連通分量前必須理解與其對應的兩個概念,連通圖(無向圖)和連通分量。 連通圖的定義是:如果一個圖中的任何一個節點可以到達其他節點,那麼它就是連通的。 例如以下圖形: 這是最簡單的一個連通圖,即使它並不閉合。由於節點間的路徑是沒有方向的,符合從任意一個節點出發,都可以到達其他剩餘的節點這 ...
  • 1. isinstance, type, issubclass isinstance: 判斷你給對象是否是xx類型的. (向上判斷 type: 返回xxx對象的數據類型 issubclass: 判斷xxx類是否xxx的子類 2. 如何區分方法和函數 在類中: 實例方法 如果是類名.方法 函數 如果是 ...
  • 1. isinstance, type, issubclass的區別 2. 反射 主要是用到了4個函數( 用的最多的就是getattr()和 hasattr() ): getattr() 從xxx對象中獲取到xxx屬性值 hasattr() 判斷xxx對象中是否有xxx屬性值 delattr() 從 ...
  • 在面向對象編程實踐中,我們通過眾多的類來組織一個複雜的系統,這些類之間相互關聯、調用使他們的關係形成了一個複雜緊密的網路。當系統啟動時,出於性能、資源利用多方面的考慮,我們不可能要求 JVM 一次性將全部的類都載入完成,而是只載入能夠支持系統順利啟動和運行的類和資源即可。那麼在系統運行過程中如果需要 ...
  • 1.成員 在類中你能寫的所有內容都是類的成員 2.變數 1. 實例變數:昨天寫的就是實力變數,由對象去訪問的變數 2. 類變數: 這個變數屬於類.但是對象也可以訪問 實例變數 class Person: def __init__(self, name, id, gender, birth): sel ...
  • 很多時候寫windows程式都需要結合多線程,在C#中用如下得代碼來創建並啟動一個新的線程。 但是很多時候,在新的線程中,我們需要與UI(Windows窗體設計器用戶界面)進行交互,在C#中不允許直接這樣做。可以參考MSDN中的描述。 “Windows 窗體”使用單線程單元 (STA) 模型,因為“ ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...