.NET Core 代碼安裝服務啟動

来源:https://www.cnblogs.com/dotnet-org-cn/archive/2019/09/22/11565702.html
-Advertisement-
Play Games

最近做了一些.NET Core的程式,有在Windows下運行的 有在CentOS 下運行的,Windows下運行的還好,對Windows下還算比較熟悉了,但CentOS 下 每次都是找筆記支持命令 於是今天晚上就乾脆把以.NET Core程式已服務形式啟動的代碼封裝了下,代碼 主要是便於安裝。 我 ...


最近做了一些.NET Core的程式,有在Windows下運行的 有在CentOS 下運行的,Windows下運行的還好,對Windows下還算比較熟悉了,但CentOS 下 每次都是找筆記支持命令

於是今天晚上就乾脆把以.NET Core程式已服務形式啟動的代碼封裝了下,代碼 主要是便於安裝。

我們寫好一個程式後 然後要已服務啟動 每次都是需要輸入命令,對於我這種不記單詞的人來說太痛苦了,

當然windows環境下命令到是很簡單。

廢話不說了 先給大家看下效果

CentOS 下的運行效果是這樣的

dotnet ConsoleApp2.dll -i 

 

進行服務的安裝

dotnet ConsoleApp2.dll -u

進行服務的卸載

 

 

 

 

安裝完成後使用 ps x 進行進程查看 是否存在。

Window 下運行效果

 

 

 安裝完成,我們在到window 服務管理工具去看看

 

 

 

 

發現已經多了一個服務,說明安裝成功了

 

然後再來分析代碼

首先CentOS 下讓程式以服務形式啟動 我們需要做以下工作

1、寫service文件

2、systemctl 啟動service

service文件內容如下:

[Unit]
Description="服務說明"      
[Service]
Type=simple
GuessMainPID=true
WorkingDirectory=//項目路徑
StandardOutput=journal
StandardError=journal
ExecStart=/usr/bin/dotnet 項目文件dll  //啟動指令
Restart=always

[Install]
WantedBy=multi-user.target

參考:http://www.jinbuguo.com/systemd/systemd.service.html

在使用systemctl 命令使其生效

systemctl enable *.service 使自啟動生效
systemctl start *.service 立即啟動項目服務

那麼結合代碼就好說了

 var servicepath = $"/etc/systemd/system/{serviceName}.service";// 創建服務文件
                    System.IO.File.WriteAllText(servicepath, $"[Unit]{Environment.NewLine}");
                    System.IO.File.AppendAllText(servicepath, $"Description={serviceDescription}{Environment.NewLine}");// 服務描述
                    System.IO.File.AppendAllText(servicepath, $"[Service]{Environment.NewLine}");
                    System.IO.File.AppendAllText(servicepath, $"Type=simple{Environment.NewLine}");//設置進程的啟動類型, 必須設為 simple, forking, oneshot, dbus, notify, idle 之一。
                    System.IO.File.AppendAllText(servicepath, $"GuessMainPID=true{Environment.NewLine}");
                    System.IO.File.AppendAllText(servicepath, $"WorkingDirectory={workingDirectory}{Environment.NewLine}");
                    System.IO.File.AppendAllText(servicepath, $"StandardOutput=journal{Environment.NewLine}");
                    System.IO.File.AppendAllText(servicepath, $"StandardError=journal{Environment.NewLine}");
                    System.IO.File.AppendAllText(servicepath, $"ExecStart=/usr/bin/dotnet {System.IO.Path.GetFileName(filePath)}{Environment.NewLine}");
                    System.IO.File.AppendAllText(servicepath, $"Restart=always{Environment.NewLine}");
                    System.IO.File.AppendAllText(servicepath, $"[Install]{Environment.NewLine}");
                    System.IO.File.AppendAllText(servicepath, $"WantedBy=multi-user.target{Environment.NewLine}");
                    Console.WriteLine(StartProcess("/usr/bin/systemctl", $"enable {serviceName}.service"));
                    Console.WriteLine(StartProcess("/usr/bin/systemctl", $"start {serviceName}.service"));
                    Console.WriteLine($"Unix 下安裝服務完成,如果失敗請手動執行以下命令完成安裝:");
                    Console.WriteLine($"systemctl enable {serviceName}.service  //使自啟動生效");
                    Console.WriteLine($"systemctl start {serviceName}.service  //立即啟動項目服務");
                    Console.WriteLine($"systemctl status {serviceName}.service -l //查看服務狀態");
View Code

這樣 我們就可以安裝並啟動服務了,

那麼windows下麵 其實根據簡單 ,就一個命令

sc  create  服務名稱 binpath=啟動文件 就可以了

當然 需要添加一個ServiceBase的子類,這裡我搞了一個通用的

代碼如下

/// <summary>
    /// Windows 服務
    /// </summary>
    class WinService : ServiceBase
    {
        private static string WinServiceName;
        private static Action<string[]> StartRun;
        public WinService()
        {
            ServiceName = WinServiceName;
        }
        /// <summary>
        /// 啟動服務
        /// </summary>
        /// <param name="args"></param>
        protected override void OnStart(string[] args)
        {
            StartRun(args);
        }
        public static void Config(Action<string[]> startRun,string serviceName)
        {
            WinServiceName = serviceName;
            StartRun = startRun;
        }
    }
View Code

這裡為什麼是Action<string[]> StartRun; 了 就是因為讓服務啟動後 執行實際要執行的代碼。

比如demo

class Program
    {
        [Description("這是一個測試服務")]
        [DisplayName("測試服務")]
        static void Main(string[] args)
        {
            DotNet.Install.ServiceInstall.Run("test", args, Run);
        }
        static void Run(string[] args)
        {
            HttpServer httpServer = new HttpServer();
            httpServer.Start();
        }
    }
View Code

服務啟動後是執行的Run方法。

WIndows下的安裝代碼那就是

/// <summary>
        /// Windows 環境下運行
        /// </summary>
        /// <param name="filePath">啟動文件</param>
        /// <param name="serviceName">服務名稱</param>
        /// <param name="displayName">顯示名稱</param>
        /// <param name="serviceDescription">服務說明</param>
        /// <param name="args"></param>
        /// <param name="startRun">實際運行方法</param>
        /// <returns></returns>
        static bool RunWin(string filePath, string serviceName,string displayName, string serviceDescription, string[] args, Action<string[]> startRun)
        {
            if (args.Length == 1)
            {
                var workingDirectory = System.IO.Path.GetDirectoryName(filePath);
                if (System.IO.File.Exists(System.IO.Path.ChangeExtension(filePath, ".exe")))//判斷是否存在exe ,如果存在則啟動exe
                {
                    filePath = System.IO.Path.ChangeExtension(filePath, ".exe");//修改尾碼名為exe
                }
                else
                {
                    var dotnetPath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "dotnet", "dotnet.exe");//查找預設軟體安裝目錄下的dotnet.exe
                    if (System.IO.File.Exists(dotnetPath))
                    {
                        filePath = $"\\\"{dotnetPath}\\\" \\\"{filePath}\\\"";
                    }
                    else
                    {
                        dotnetPath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "dotnet", "dotnet.exe");//為了防止有的人只裝了x86位的,所以查找x86下的軟體安裝目錄下的dotnet.exe
                        if (System.IO.File.Exists(dotnetPath))
                        {
                            filePath = $"\\\"{dotnetPath}\\\" \\\"{filePath}\\\"";
                        }
                        else
                        {
                            Console.WriteLine($"系統無法定位DotNet Core的安裝目錄。");
                            return true;
                        }
                    }
                }
                if (args[0].Equals("-i", StringComparison.OrdinalIgnoreCase))
                {
                    if (!AdminRestartApp(filePath, args))
                    {
                        return true;
                    }
                    Console.WriteLine(StartProcess("sc.exe", $"create {serviceName} binpath=\"{filePath}\" start=auto DisplayName=\"{displayName}\""));
                    Console.WriteLine($"Windows 下安裝服務完成,如果失敗請手動執行以下命令完成安裝:");
                    Console.WriteLine($"sc create {serviceName} binpath=\"{filePath}\" start=auto DisplayName=\"{displayName}\" //安裝服務");
                    using (var service = Registry.LocalMachine.OpenSubKey($@"SYSTEM\CurrentControlSet\Services\{serviceName}", true))
                    {
                        service.SetValue("Description", serviceDescription);
                    }
                    return true;
                }
                else if (args[0].Equals("-u", StringComparison.OrdinalIgnoreCase))
                {
                    if (!AdminRestartApp(filePath, args))
                    {
                        return true;
                    }
                    Console.WriteLine(StartProcess("sc.exe", $"delete {serviceName}"));
                    Console.WriteLine($"Windows 下卸載服務完成,如果失敗請手動執行以下命令完成卸載:");
                    Console.WriteLine($"sc delete {serviceName}  //卸載服務");
                    return true;
                }
            }
            WinService.Config(startRun, serviceName);
            using (var service = new WinService())
            {
                System.ServiceProcess.ServiceBase.Run(service);
            }
            return false;
        }
View Code

這樣我們就完美了

在放上整個代碼:

/**************************************************************
* Copyright (C) 2019 www.hnlyf.com 版權所有(盜版必究)
*
* 作者: 李益芬(QQ 12482335)
* 創建時間: 2019/09/22 22:40:15
* 文件名: 
* 描述: 
* 
* 修改歷史
* 修改人:
* 時間:
* 修改說明:
*
**************************************************************/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Linq;
using System.ComponentModel;
using Microsoft.Win32;

namespace DotNet.Install
{
    /// <summary>
    /// 服務安裝
    /// </summary>
    public static class ServiceInstall
    {
        /// <summary>
        /// Windows 環境下運行
        /// </summary>
        /// <param name="filePath">啟動文件</param>
        /// <param name="serviceName">服務名稱</param>
        /// <param name="displayName">顯示名稱</param>
        /// <param name="serviceDescription">服務說明</param>
        /// <param name="args"></param>
        /// <param name="startRun">實際運行方法</param>
        /// <returns></returns>
        static bool RunWin(string filePath, string serviceName,string displayName, string serviceDescription, string[] args, Action<string[]> startRun)
        {
            if (args.Length == 1)
            {
                var workingDirectory = System.IO.Path.GetDirectoryName(filePath);
                if (System.IO.File.Exists(System.IO.Path.ChangeExtension(filePath, ".exe")))//判斷是否存在exe ,如果存在則啟動exe
                {
                    filePath = System.IO.Path.ChangeExtension(filePath, ".exe");//修改尾碼名為exe
                }
                else
                {
                    var dotnetPath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "dotnet", "dotnet.exe");//查找預設軟體安裝目錄下的dotnet.exe
                    if (System.IO.File.Exists(dotnetPath))
                    {
                        filePath = $"\\\"{dotnetPath}\\\" \\\"{filePath}\\\"";
                    }
                    else
                    {
                        dotnetPath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "dotnet", "dotnet.exe");//為了防止有的人只裝了x86位的,所以查找x86下的軟體安裝目錄下的dotnet.exe
                        if (System.IO.File.Exists(dotnetPath))
                        {
                            filePath = $"\\\"{dotnetPath}\\\" \\\"{filePath}\\\"";
                        }
                        else
                        {
                            Console.WriteLine($"系統無法定位DotNet Core的安裝目錄。");
                            return true;
                        }
                    }
                }
                if (args[0].Equals("-i", StringComparison.OrdinalIgnoreCase))
                {
                    if (!AdminRestartApp(filePath, args))
                    {
                        return true;
                    }
                    Console.WriteLine(StartProcess("sc.exe", $"create {serviceName} binpath=\"{filePath}\" start=auto DisplayName=\"{displayName}\""));
                    Console.WriteLine($"Windows 下安裝服務完成,如果失敗請手動執行以下命令完成安裝:");
                    Console.WriteLine($"sc create {serviceName} binpath=\"{filePath}\" start=auto DisplayName=\"{displayName}\" //安裝服務");
                    using (var service = Registry.LocalMachine.OpenSubKey($@"SYSTEM\CurrentControlSet\Services\{serviceName}", true))
                    {
                        service.SetValue("Description", serviceDescription);
                    }
                    return true;
                }
                else if (args[0].Equals("-u", StringComparison.OrdinalIgnoreCase))
                {
                    if (!AdminRestartApp(filePath, args))
                    {
                        return true;
                    }
                    Console.WriteLine(StartProcess("sc.exe", $"delete {serviceName}"));
                    Console.WriteLine($"Windows 下卸載服務完成,如果失敗請手動執行以下命令完成卸載:");
                    Console.WriteLine($"sc delete {serviceName}  //卸載服務");
                    return true;
                }
            }
            WinService.Config(startRun, serviceName);
            using (var service = new WinService())
            {
                System.ServiceProcess.ServiceBase.Run(service);
            }
            return false;
        }
        /// <summary>
        /// Unix環境下運行
        /// </summary>
        /// <param name="filePath"></param>
        /// <param name="serviceName"></param>
        /// <param name="serviceDescription"></param>
        /// <param name="args"></param>
        /// <param name="startRun"></param>
        /// <returns></returns>
        static bool RunUnix(string filePath, string serviceName, string serviceDescription, string[] args, Action<string[]> startRun)
        {
            var workingDirectory = System.IO.Path.GetDirectoryName(filePath);
            if (args.Length == 1)
            {
                if (args[0].Equals("-i", StringComparison.OrdinalIgnoreCase))
                {
                    var servicepath = $"/etc/systemd/system/{serviceName}.service";// 創建服務文件
                    System.IO.File.WriteAllText(servicepath, $"[Unit]{Environment.NewLine}");
                    System.IO.File.AppendAllText(servicepath, $"Description={serviceDescription}{Environment.NewLine}");// 服務描述
                    System.IO.File.AppendAllText(servicepath, $"[Service]{Environment.NewLine}");
                    System.IO.File.AppendAllText(servicepath, $"Type=simple{Environment.NewLine}");//設置進程的啟動類型, 必須設為 simple, forking, oneshot, dbus, notify, idle 之一。
                    System.IO.File.AppendAllText(servicepath, $"GuessMainPID=true{Environment.NewLine}");
                    System.IO.File.AppendAllText(servicepath, $"WorkingDirectory={workingDirectory}{Environment.NewLine}");
                    System.IO.File.AppendAllText(servicepath, $"StandardOutput=journal{Environment.NewLine}");
                    System.IO.File.AppendAllText(servicepath, $"StandardError=journal{Environment.NewLine}");
                    System.IO.File.AppendAllText(servicepath, $"ExecStart=/usr/bin/dotnet {System.IO.Path.GetFileName(filePath)}{Environment.NewLine}");
                    System.IO.File.AppendAllText(servicepath, $"Restart=always{Environment.NewLine}");
                    System.IO.File.AppendAllText(servicepath, $"[Install]{Environment.NewLine}");
                    System.IO.File.AppendAllText(servicepath, $"WantedBy=multi-user.target{Environment.NewLine}");
                    Console.WriteLine(StartProcess("/usr/bin/systemctl", $"enable {serviceName}.service"));
                    Console.WriteLine(StartProcess("/usr/bin/systemctl", $"start {serviceName}.service"));
                    Console.WriteLine($"Unix 下安裝服務完成,如果失敗請手動執行以下命令完成安裝:");
                    Console.WriteLine($"systemctl enable {serviceName}.service  //使自啟動生效");
                    Console.WriteLine($"systemctl start {serviceName}.service  //立即啟動項目服務");
                    Console.WriteLine($"systemctl status {serviceName}.service -l //查看服務狀態");
                    return true;
                }
                else if (args[0].Equals("-u", StringComparison.OrdinalIgnoreCase))
                {
                    var servicepath = $"/etc/systemd/system/{serviceName}.service";
                    Console.WriteLine(StartProcess("/usr/bin/systemctl", $"disable {serviceName}.service"));
                    if (System.IO.File.Exists(servicepath))
                    {
                        System.IO.File.Delete(servicepath);
                    }
                    Console.WriteLine($"Unix 下卸載服務完成,如果失敗請手動執行以下命令完成卸載");
                    Console.WriteLine($"systemctl disable {serviceName}.service  //使自啟動失效");
                    Console.WriteLine($"rm -y {servicepath}  //刪除服務文件");
                    return true;
                }
            }
            startRun(args);
            System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
            return false;
        }
        /// <summary>
        /// 運行程式,如果有命令-i或者-u則執行安裝或卸載,否則執行<paramref name="startRun"/>
        /// <para>請在Main函數中調用,服務顯示名稱請在Main函數增加[DisplayName()]特性,服務說明[Description]特性。</para>
        /// <para>Windiows下需要依賴System.ServiceProcess.ServiceController</para>
        /// <para>-i 表示安裝服務</para>
        /// <para>-u 表示卸載服務</para>
        /// </summary>
        /// <param name="serviceName">服務名稱</param>
        /// <param name="args">啟動程式的參數</param>
        /// <param name="startRun">實際程式運行的函數</param>
        public static void Run(string serviceName, string[] args, Action<string[]> startRun)
        {
            bool finish = false;
            string serviceDescription = serviceName;
            string displayName = serviceName;
            string filePath = string.Empty;
            if (args.Length == 1)
            {
                StackFrame frame = new StackFrame(1);
                if (string.IsNullOrWhiteSpace(serviceName))
                {
                    serviceName=frame.GetMethod().DeclaringType.Assembly.GetName().Name;
                }
                var displayNames = frame.GetMethod().GetCustomAttributes(typeof(DisplayNameAttribute), true);
                if (displayNames.Length > 0)
                {
                    displayName = (displayNames[0] as DisplayNameAttribute).DisplayName;
                }
                var descriptions = frame.GetMethod().GetCustomAttributes(typeof(DescriptionAttribute), true);
                if (descriptions.Length > 0)
                {
                    serviceDescription = (descriptions[0] as DescriptionAttribute).Description;
                }
                filePath = frame.GetMethod().DeclaringType.Assembly.Location;
            }
            if (Environment.OSVersion.Platform == PlatformID.Win32NT)
            {
                finish = RunWin(filePath, serviceName, displayName, serviceDescription, args, startRun);
            }
            else
            {
                finish = RunUnix(filePath, serviceName, serviceDescription, args, startRun);
            }
        }
        static string StartProcess(string fileName, string arguments)
        {
            string output = string.Empty;
            using (System.Diagnostics.Process process = new System.Diagnostics.Process())
            {
                process.StartInfo = new ProcessStartInfo
                {
                    UseShellExecute = false,
                    Arguments = arguments,
                    RedirectStandardInput = true,
                    RedirectStandardOutput = true,
                    RedirectStandardError = true,
                    CreateNoWindow = true,
                    WorkingDirectory = Environment.CurrentDirectory,
                    FileName = fileName,
                };
                process.Start();//啟動程式
                process.WaitForExit();//等待程式執行完退出進程
                output = process.StandardOutput.ReadToEnd();
                process.Close();
            }
            return output;
        }
        static bool AdminRestartApp(string filePath,string[] args)
        {
            if (!IsAdmin())
            {
                Console.WriteLine("重新已管理員啟動" + filePath);
                ProcessStartInfo startInfo = new ProcessStartInfo
                {
                    UseShellExecute = true,
                    Arguments = string.Join(" ", args),
                    WorkingDirectory = Environment.CurrentDirectory,
                    FileName = filePath,
                    Verb = "runas"
                };
                try
                {
                    Process.Start(startInfo);
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"重新已管理員啟動失敗:{ex}");
                }
                return false;
            }
            return true;
        }
        /// <summary>
        /// 判斷是否是處於Administrator下允許
        /// </summary>
        /// <returns></returns>
        static bool IsAdmin()
        {
            using (System.Security.Principal.WindowsIdentity wi = System.Security.Principal.WindowsIdentity.GetCurrent())
            {
                System.Security.Principal.WindowsPrincipal wp = new System.Security.Principal.WindowsPrincipal(wi);
                return wp.IsInRole(System.Security.Principal.WindowsBuiltInRole.Administrator);
            }
        }
    }
}
View Code

最後把dll 上轉到nuget 上面 DotNetCN.Install

源代碼放到github上面:https://github.com/hnlyf/DotNet.Install

 


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

-Advertisement-
Play Games
更多相關文章
  • 聲明 :本博客僅僅是一個初學者的學習記錄、心得總結,其中肯定有許多錯誤,不具有參考價值,歡迎大佬指正,謝謝!想和我交流、一起學習、一起進步的朋友可以加我微信Liu__66666666 這是簡單學習一遍之後的記錄,後期還會修改。 一、學習內容 1. "jvm簡介" 2. 記憶體模型 3. 垃圾回收機制 ...
  • 恢復內容開始 目錄 1. 分支結構 1.1 初步介紹 1.2 使用案例 1.3 練習 2.迴圈結構 1.1 初步介紹 1.2 使用案例 目錄 1. 分支結構 1.1 初步介紹 1.2 使用案例 1.3 練習 2.迴圈結構 1.1 初步介紹 1.2 使用案例 1. 分支結構 1.1 初步介紹 1.2 ...
  • ZooKeeper技術的極少以及ZooKeeper集群的搭建 ...
  • 0. 序 我從一生下來就呆在這個昏暗的地方。 我不明白為什麼程式員這麼喜歡 Dark Mode,Brighten Mode 才是我的最愛。聽說最近連 iphone 都開始支持 Dark Mode 了,沒話講。。。說好的絕不妥協呢? 我周圍是熙熙攘攘的函數群,穿插著變數聲明和巨集定義。 在我們這裡,函數 ...
  • 一、前言 應聘IC前端相關崗位時,FIFO是最常考也是最基本的題目。FIFO經常用於數據緩存、位寬轉換、非同步時鐘域處理。隨著晶元規模的快速增長,靈活的system verilog成為設計/驗證人員的基本功。本文從簡易版的同步FIFO開始,熟悉IP設計與驗證的基礎技能。 二、IP設計 FIFO這一IP ...
  • 背景 運維人員反饋一個容器化的java程式每跑一段時間就會出現OOM問題,重啟後,間隔大概兩天後復現。 問題調查 一查日誌 由於是容器化部署的程式,登上主機後使用docker logs ContainerId查看輸出日誌,並沒有發現任何異常輸出。 使用docker stats查看容器使用的資源情況, ...
  • #set指令 #set指令用於向一個變數或者對象賦值。 格式: #set($var = value) LHS是一個變數,不要使用特殊字元例如英文句號等,不能用大括弧括起來。測試發現#set($user.name = 'zhangsan'),#set(${age} = 18)均賦值失敗。 RHS可以是 ...
  • 前言 說實話,這章本來不打算講的,因為配置多數據源的網上有很多類似的教程。但是最近因為項目要用到分庫分表,所以讓我研究一下看怎麼實現。我想著上一篇博客講了多環境的配置,不同的環境調用不同的資料庫,那接下來就將一個環境用到多個庫也就講了。所以才有了這篇文章。 我們先來看一下今天項目的項目結構,在上篇博 ...
一周排行
    -Advertisement-
    Play Games
  • 基於.NET Framework 4.8 開發的深度學習模型部署測試平臺,提供了YOLO框架的主流系列模型,包括YOLOv8~v9,以及其系列下的Det、Seg、Pose、Obb、Cls等應用場景,同時支持圖像與視頻檢測。模型部署引擎使用的是OpenVINO™、TensorRT、ONNX runti... ...
  • 十年沉澱,重啟開發之路 十年前,我沉浸在開發的海洋中,每日與代碼為伍,與演算法共舞。那時的我,滿懷激情,對技術的追求近乎狂熱。然而,隨著歲月的流逝,生活的忙碌逐漸占據了我的大部分時間,讓我無暇顧及技術的沉澱與積累。 十年間,我經歷了職業生涯的起伏和變遷。從初出茅廬的菜鳥到逐漸嶄露頭角的開發者,我見證了 ...
  • C# 是一種簡單、現代、面向對象和類型安全的編程語言。.NET 是由 Microsoft 創建的開發平臺,平臺包含了語言規範、工具、運行,支持開發各種應用,如Web、移動、桌面等。.NET框架有多個實現,如.NET Framework、.NET Core(及後續的.NET 5+版本),以及社區版本M... ...
  • 前言 本文介紹瞭如何使用三菱提供的MX Component插件實現對三菱PLC軟元件數據的讀寫,記錄了使用電腦模擬,模擬PLC,直至完成測試的詳細流程,並重點介紹了在這個過程中的易錯點,供參考。 用到的軟體: 1. PLC開發編程環境GX Works2,GX Works2下載鏈接 https:// ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • 1、jQuery介紹 jQuery是什麼 jQuery是一個快速、簡潔的JavaScript框架,是繼Prototype之後又一個優秀的JavaScript代碼庫(或JavaScript框架)。jQuery設計的宗旨是“write Less,Do More”,即倡導寫更少的代碼,做更多的事情。它封裝 ...
  • 前言 之前的文章把js引擎(aardio封裝庫) 微軟開源的js引擎(ChakraCore))寫好了,這篇文章整點js代碼來測一下bug。測試網站:https://fanyi.youdao.com/index.html#/ 逆向思路 逆向思路可以看有道翻譯js逆向(MD5加密,AES加密)附完整源碼 ...
  • 引言 現代的操作系統(Windows,Linux,Mac OS)等都可以同時打開多個軟體(任務),這些軟體在我們的感知上是同時運行的,例如我們可以一邊瀏覽網頁,一邊聽音樂。而CPU執行代碼同一時間只能執行一條,但即使我們的電腦是單核CPU也可以同時運行多個任務,如下圖所示,這是因為我們的 CPU 的 ...
  • 掌握使用Python進行文本英文統計的基本方法,並瞭解如何進一步優化和擴展這些方法,以應對更複雜的文本分析任務。 ...
  • 背景 Redis多數據源常見的場景: 分區數據處理:當數據量增長時,單個Redis實例可能無法處理所有的數據。通過使用多個Redis數據源,可以將數據分區存儲在不同的實例中,使得數據處理更加高效。 多租戶應用程式:對於多租戶應用程式,每個租戶可以擁有自己的Redis數據源,以確保數據隔離和安全性。 ...