<repo_name>goodapiyes/LinuxCmd.Net<file_sep>/LinuxCmd.Net/Models/LinuxVmstatInfo.cs
﻿namespace LinuxCmd.Net.Models
{
    public class LinuxVmstatInfo
    {
        /// <summary>
        /// 处于运行的状态的进程数
        /// </summary>
        public int run { get; set; }
        /// <summary>
        /// 进程被cpu以外的状态给阻断了，
        /// 比如是硬盘，网络，当我们进程发一个数据包，网速快很快就能发完
        /// 但是当网速太慢，就会导致b的状态
        /// </summary>
        public int block { get; set; }
        /// <summary>
        /// 磁盘读取总量 kb/s
        /// </summary>
        public int bi { get; set; }
        /// <summary>
        /// 磁盘写入总量 kb/s
        /// </summary>
        public int bo { get; set; }
    }
}<file_sep>/LinuxCmd.Net.NetWork/NetWorker.cs
﻿using System;
using System.IO;
using System.Threading;
using Microsoft.Extensions.Configuration;

namespace LinuxCmd.Net.NetWork
{
    public class NetWorker 
    {
        public MasterHandler Master { get; private set; }
        public ClientHandler Client { get; private set; }

        public void Start()
        {
            if (ConfigHander.GetString("type") == "master")
                InitMaster();
            else if (ConfigHander.GetString("type") == "worker")
                InitClient();
        }
        private void InitMaster()
        {
            Master = new MasterHandler();
            Master.Listening();
        }

        private void InitClient()
        {
            Client =new ClientHandler();
            Client.Start();
        }
        
        public bool Dispose()
        {
            if (ConfigHander.GetString("type") == "master")
                Master.Dispose();
            else if (ConfigHander.GetString("type") == "worker")
                Client.Dispose();
            return true;
        }
    }
}<file_sep>/LinuxCmd.Net.ZTest/Program.cs
﻿using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using LinuxCmd.Net;
using LinuxCmd.Net.Commads;
using LinuxCmd.Net.Models;


namespace LinuxCmd.Net.ZTest
{
    class Program
    {
        //you can’t get to run on Windows
        static void Main(string[] args)
        {

            //string text = File.ReadAllText("text.txt");

            //redirect:true 获取服务器命令执行结果
            var ls = "ls".LinuxBash().Output;

            //redirect:false 将命令执行结果重定向输出到服务器
            ls = "ls".LinuxBash(false).Output;

            //服务器状态对象
            LinuxServerInfo server = new LinuxServerInfo();

            //系统信息
            var OSName = server.OSName;
            $"echo {OSName}".LinuxBash(false);

            //运行时长
            var RunTime = server.RunTime;
            $"echo {RunTime}".LinuxBash(false);

            //系统负载
            var LoadAverages = server.LoadAverages;
            $"echo {LoadAverages}".LinuxBash(false);

            //CPU状态: cpu描述,cpu核心数,cpu使用率
            var cpuInfo = server.Cpu;
            $"echo {cpuInfo.SerializeJSON().Replace('(',' ').Replace(')',' ')}".LinuxBash(false);

            //内存状态:内存总容量,实际可用容量,已使用的容量,缓存化的容量,系统缓冲容量
            var Mem = server.Mem;
            $"echo {Mem.SerializeJSON()}".LinuxBash(false);

            //磁盘状态:磁盘总容量,已用容量,可用容量,已用百分比
            var Disk = server.Disk;
            $"echo {Disk.SerializeJSON()}".LinuxBash(false);

            //IO读写状态:读请求数量,写请求数量,读字节数,写字节数
            var IO = server.IO;
            $"echo {IO.SerializeJSON()}".LinuxBash(false);

            //网络状态:接收的数据包数量,发送的数据包数量,接收字节数,发送字节数
            var NetWork = server.NetWork;
            $"echo {NetWork.SerializeJSON()}".LinuxBash(false);

            //网络连接状态: tcp客户端IP,服务器IP,连接状态
            var NetworkConnections = server.NetworkConnections;
            foreach (var net in NetworkConnections)
            {
                $"echo {net.SerializeJSON()}".LinuxBash(false);
            }

            //进程列表:进程id,进程所有者的用户名,虚拟内存使用量,物理内存使用量,进程状态,CPU使用率,进程命令名
            var Tasks = server.Tasks;
            for (int i = 0; i < 6; i++)
            {
                $"echo {Tasks[i].SerializeJSON()}".LinuxBash(false);
            }

            

            Console.WriteLine("Press any key to exit");
            Console.ReadLine();
        }
    }

    public static class JsonHelper
    {

        public static string SerializeJSON<T>(this T data)
        {
            return Newtonsoft.Json.JsonConvert.SerializeObject(data);
        }

         public static T DeserializeJSON<T>(this string json)
        {
            return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(json);
        }

    }
}
<file_sep>/LinuxCmd.Net/Commads/Sar.cs
﻿using System;
using System.Text.RegularExpressions;
using LinuxCmd.Net.Models;

namespace LinuxCmd.Net.Commads
{
    public class Sar
    {
        public virtual LinuxSarInfo GetLinuxSarInfo(string input)
        {
            Match match = Regex.Match(input, @"Average:\s+eth0\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)");
            if (match.Success)
            {
                LinuxSarInfo info = new LinuxSarInfo();
                info.ReceivedPacket = Convert.ToDouble(match.Groups[1].Value);
                info.SentPacket = Convert.ToDouble(match.Groups[2].Value);
                info.ReceivedBytes = Convert.ToDouble(match.Groups[3].Value);
                info.SentBytes = Convert.ToDouble(match.Groups[4].Value);
                return info;
            }
            return null;
        }
    }
}<file_sep>/LinuxCmd.Net/Models/LinuxSarInfo.cs
﻿namespace LinuxCmd.Net.Models
{
    public class LinuxSarInfo
    {
        /// <summary>
        /// 接收的数据包
        /// </summary>
        public double ReceivedPacket { get; set; }
        /// <summary>
        /// 发送的数据包
        /// </summary>
        public double SentPacket { get; set; }
        /// <summary>
        /// 接收的字节数 kb/s
        /// </summary>
        public double ReceivedBytes { get; set; }
        /// <summary>
        /// 发送的字节数 kb/s
        /// </summary>
        public double SentBytes { get; set; }
    }
}<file_sep>/LinuxCmd.Net/Models/LinuxDfInfo.cs
﻿namespace LinuxCmd.Net.Models
{
    public class LinuxDfInfo
    {
        /// <summary>
        /// 文件系统
        /// </summary>
        public string Filesystem { get; set; }
        /// <summary>
        /// 容量 MB
        /// </summary>
        public double Size { get; set; }
        /// <summary>
        /// 已用 MB
        /// </summary>
        public double Used { get; set; }
        /// <summary>
        /// 可用 MB
        /// </summary>
        public double Avail { get; set; }
        /// <summary>
        /// 已用%
        /// </summary>
        public double UseUsage { get; set; }
        /// <summary>
        /// 挂载点
        /// </summary>
        public string Mounted { get; set; }
    }
}<file_sep>/LinuxCmd.Net/Commads/Vmstat.cs
﻿using System;
using System.Text.RegularExpressions;
using LinuxCmd.Net.Models;

namespace LinuxCmd.Net.Commads
{
    public class Vmstat
    {
        public virtual LinuxVmstatInfo GetLinuxVmstatInfo(string input)
        {
            Match match = Regex.Match(input, @"(\d+)\s+(\d+)\s+\d+\s+\d+\s+\d+\s+\d+\s+\d+\s+\d+\s+(\d+)\s+(\d+)");
            if (match.Success)
            {
                LinuxVmstatInfo info = new LinuxVmstatInfo();
                info.run = Convert.ToInt32(match.Groups[1].Value);
                info.block = Convert.ToInt32(match.Groups[2].Value);
                info.bi = Convert.ToInt32(match.Groups[3].Value);
                info.bo = Convert.ToInt32(match.Groups[4].Value);
                return info;
            }
            return null;
        }
    }
}<file_sep>/LinuxCmd.Net.NetWork/MasterHandler.cs
﻿using System;
using System.Collections.Concurrent;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Cowboy.Sockets.Core;

namespace LinuxCmd.Net.NetWork
{
    public class MasterHandler
    {
        public string Ip { get; private set; }
        public int? Port { get; private set; }
        public TcpSocketServer Server;
        public ConcurrentDictionary<string, TcpSocketSession> Sessions { get; private set; }
        public MasterHandler()
        {
            this.Ip = ConfigHander.GetString("master:ip");
            this.Port = ConfigHander.GetInt("master:port");
            Sessions=new ConcurrentDictionary<string, TcpSocketSession>();
        }

        public void Listening()
        {
            if (string.IsNullOrEmpty(Ip) || !Port.HasValue)
            {
                LogHelper.Logger.Error("ip,port is not available !!!");
                throw new Exception("ip,port is not available !!!");
            }

            var config = new TcpSocketServerConfiguration();
            Server = new TcpSocketServer(IPAddress.Parse(Ip), Port.Value, config);
            Server.ClientConnected += ClientConnected;
            Server.ClientDisconnected += ClientDisconnected;
            Server.ClientDataReceived += ClientDataReceived;
            Server.Listen();
            LogHelper.Logger.Information("Server Listening...");
        }

        public bool Issue(string ip,string cmd)
        {
            try
            {
                foreach (var session in Sessions)
                {
                    if(session.Key.Contains(ip))
                        Server.SendTo(session.Value.SessionKey,Encoding.UTF8.GetBytes(cmd));
                }
            }
            catch (Exception e)
            {
                LogHelper.Logger.Error($"Issue {ip},Error:{e.Message},{e.StackTrace}");
                return false;
            }
            return true;
        }

        private void ClientConnected(object sender, TcpClientConnectedEventArgs e)
        {
            
            var key = e.Session.RemoteEndPoint.ToString();
            Sessions.AddOrUpdate(key, e.Session, (k, o) => o);
            Console.WriteLine($"客户端 {e.Session.RemoteEndPoint} 已连接 {e.Session}.");
        }

        private void ClientDisconnected(object sender, TcpClientDisconnectedEventArgs e)
        {
            var key = e.Session.RemoteEndPoint.ToString();
            TcpSocketSession removeSession;
            if(Sessions.ContainsKey(key))
                Sessions.TryRemove(key, out removeSession);
            Console.WriteLine($"客户端 {e.Session} 关闭了连接.");
        }

        private void ClientDataReceived(object sender, TcpClientDataReceivedEventArgs e)
        {
            var text = Encoding.UTF8.GetString(e.Data, e.DataOffset, e.DataLength);
            Console.Write(string.Format("客户端 : {0} {1} --> ", e.Session.RemoteEndPoint, e.Session));
            if (e.DataLength < 256)
            {
                Console.WriteLine(text);
            }
            else
            {
                Console.WriteLine("{0} Bytes", e.DataLength);
            }

            Server.SendTo(e.Session, Encoding.UTF8.GetBytes("ok"));
        }

        public void Dispose()
        {
            Server.Shutdown();
            Server = null;
        }
    }
}<file_sep>/LinuxCmd.Net/Commads/Netstat.cs
﻿using System.Collections.Generic;
using System.Text.RegularExpressions;
using LinuxCmd.Net.Models;

namespace LinuxCmd.Net.Commads
{
    public class Netstat
    {
        public virtual List<LinuxNetstatInfo> GetLinuxNetstatInfos(string input)
        {
            MatchCollection matches = Regex.Matches(input, @"(tcp)\s+\d+\s+\d+\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)");
            List<LinuxNetstatInfo> list = new List<LinuxNetstatInfo>();
            foreach (Match match in matches)
            {
                if (match.Success)
                {
                    LinuxNetstatInfo info = new LinuxNetstatInfo();
                    info.Proto = match.Groups[1].Value;
                    info.LocalAddress = match.Groups[2].Value;
                    info.ForeignAddress = match.Groups[3].Value;
                    info.State = match.Groups[4].Value;
                    info.ProgramName = match.Groups[5].Value;
                    list.Add(info);
                }
            }
            return list;
        }
    }
}<file_sep>/LinuxCmd.Net.NetWork/CommandHandler.cs
﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using Newtonsoft.Json;

namespace LinuxCmd.Net.NetWork
{
    public class CommandHandler
    {
        public static string HeartBeatCmd()
        {
            //if (!RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            //    return "not support for current os";
            LinuxServerInfo info = new LinuxServerInfo();
            StringBuilder builder = new StringBuilder();
            if (!RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
                return $"{CommandTag.HeartBeat.GetValue()}|0|End";
            //测试
            //builder.AppendFormat("|{0}", "CentOS Linux release 7.6.1810");
            //builder.AppendFormat("|{0}", "9天 7小时 09分钟");
            //builder.AppendFormat("|{0}", "1.13,1.33,1.55");
            //builder.AppendFormat("|{0}", "10");
            //builder.AppendFormat("|{0}", "3.1");
            //builder.AppendFormat("|{0}", "1");
            //builder.AppendFormat("|{0}", "7686788,12555555");
            //builder.AppendFormat("|End");
            builder.AppendFormat("{0}|{1}", CommandTag.HeartBeat.GetValue(),1);
            builder.AppendFormat("|{0}", info.OSName);
            builder.AppendFormat("|{0}", info.RunTime);
            builder.AppendFormat("|{0}", info.LoadAverages);
            builder.AppendFormat("|{0}", info.Cpu.CpuUsage);
            builder.AppendFormat("|{0}", info.Mem?.MemUsage);
            builder.AppendFormat("|{0}", info.Disk?.UseUsage);
            builder.AppendFormat("|{0},{1}", info.IO?.ReadBytes, info.IO?.WriteBytes);
            builder.AppendFormat("|End");
            return builder.ToString();
        }

        public static string GetCmdName(string data)
        {
            if (!data.Contains('|'))
                return null;
            return data.Split('|')[0];
        }
        public static bool GetCmdValid(string data)
        {
            if (!data.Contains('|'))
                return false;
            return data.Split('|')[1].Contains("1");
        }
    }

    public enum CommandTag
    {
        HeartBeat = 1001
    }

    public static class Extensions
    {
        public static int GetValue(this Enum instance)
        {
            return (int)System.Enum.Parse(instance.GetType(), instance.ToString(), true);
        }

        public static T ExToObject<T>(this string json)
        {
            return ToObject<T>(json);
        }

        public static string ExToJson(this object obj)
        {
            return ToJson(obj);
        }

        /// <summary>
        ///     将Json字符串转换为对象
        /// </summary>
        /// <param name="json">Json字符串</param>
        public static T ToObject<T>(string json)
        {
            if (string.IsNullOrWhiteSpace(json))
                return default(T);
            return JsonConvert.DeserializeObject<T>(json);
        }

        /// <summary>
        ///     将对象转换为Json字符串
        /// </summary>
        /// <param name="target">目标对象</param>
        /// <param name="isConvertToSingleQuotes">是否将双引号转成单引号</param>
        public static string ToJson(object target, bool isConvertToSingleQuotes = false)
        {
            if (target == null)
                return "{}";
            var result = JsonConvert.SerializeObject(target);
            if (isConvertToSingleQuotes)
                result = result.Replace("\"", "'");
            return result;
        }
    }

}<file_sep>/LinuxCmd.Net/Models/LinuxTopInfo.cs
﻿using System.Collections.Generic;

namespace LinuxCmd.Net.Models
{
    public class LinuxTopInfo
    {
        #region 运行时间,运行状态,负载
        /// <summary>
        /// 统计时间
        /// </summary>
        public string Time { get; set; }
        /// <summary>
        /// 服务器运行天数
        /// </summary>
        public int Days { get; set; }
        /// <summary>
        /// 当前服务器SSH登录人数
        /// </summary>
        public int Users { get; set; }
        /// <summary>
        /// 当前服务器负载
        /// </summary>
        public string Averages { get; set; }
        #endregion

        #region 进程统计
        /// <summary>
        /// 进程总数
        /// </summary>
        public int TaskTotal { get; set; }
        /// <summary>
        /// 正在运行进程数
        /// </summary>
        public int RunningCount { get; set; }
        /// <summary>
        /// 睡眠进程数
        /// </summary>
        public int SleepingCount { get; set; }
        /// <summary>
        /// 停止进程数
        /// </summary>
        public int StoppedCount { get; set; }
        /// <summary>
        /// 僵尸进程数
        /// </summary>
        public int ZombieCount { get; set; }
        #endregion

        #region cpu统计
        /// <summary>
        /// 用户空间占用CPU百分比
        /// </summary>
        public double UserCpu { get; set; }
        /// <summary>
        /// 内核空间占用CPU百分比
        /// </summary>
        public double SystemCpu { get; set; }
        /// <summary>
        /// 用户进程空间内改变过优先级的进程占用CPU百分比
        /// </summary>
        public double NiCpu { get; set; }
        /// <summary>
        /// 空闲CPU百分比
        /// </summary>
        public double FreeCpu { get; set; }
        /// <summary>
        /// 等待输入输出的CPU时间百分比
        /// </summary>
        public double WaitCpu { get; set; }
        #endregion

        #region 物理内存统计
        /// <summary>
        /// 物理内存总量
        /// </summary>
        public double MemTotal { get; set; }
        /// <summary>
        /// 空闲内存总量
        /// </summary>
        public double MemFree { get; set; }
        /// <summary>
        /// 使用的物理内存总量
        /// </summary>
        public double MemUsed { get; set; }
        /// <summary>
        /// 用作内核缓存的内存量
        /// </summary>
        public double MemCache { get; set; }
        #endregion

        #region 虚拟内存统计
        /// <summary>
        /// 交换分区总量
        /// </summary>
        public double SwapTotal { get; set; }
        /// <summary>
        /// 空闲交换区总量
        /// </summary>
        public double SwapFree { get; set; }
        /// <summary>
        /// 使用的交换区总量
        /// </summary>
        public double SwapUsed { get; set; }
        /// <summary>
        /// 缓冲的交换区总量。
        /// </summary>
        public double SwapCache { get; set; }
        #endregion
        /// <summary>
        /// 进程信息列表
        /// </summary>
        public List<LinuxTopInfo_TaskDetail> TaskDetails { get; set; }
    }

    public class LinuxTopInfo_TaskDetail
    {
        /// <summary>
        /// 进程id
        /// </summary>
        public string Pid { get; set; }
        /// <summary>
        /// 进程所有者的用户名
        /// </summary>
        public string User { get; set; }
        /// <summary>
        /// 进程使用的虚拟内存总量 
        /// </summary>
        public double Virt { get; set; }
        /// <summary>
        /// 进程使用的、未被换出的物理内存大小
        /// </summary>
        public double Res { get; set; }
        /// <summary>
        /// 共享内存大小
        /// </summary>
        public double Shr { get; set; }
        /// <summary>
        ///进程状态。
        ///D=    不可中断的睡眠状态
        ///R=    运行
        ///S=    睡眠
        ///T=    跟踪/停止
        ///Z=    僵尸进程
        /// </summary>
        public string Status { get; set; }
        /// <summary>
        /// 上次更新到现在的CPU时间占用百分比
        /// </summary>
        public double Cpu { get; set; }
        /// <summary>
        /// 进程使用的物理内存百分比
        /// </summary>
        public double Mem { get; set; }
        /// <summary>
        /// 进程使用的CPU时间总计
        /// </summary>
        public string Time { get; set; }
        /// <summary>
        /// 命令名/命令行
        /// </summary>
        public string Commad { get; set; }
    }
}
<file_sep>/MySocket-master/README.md
Socket服务端与客户端的封装，支持.NETCore

# 安装

> Install-Package MySocket

# 服务端(多线程)

```csharp
var server = new ServerSocket(19990); //监听0.0.0.0:19990
server.Receive += (a, b) => {
	Console.WriteLine("{0} 接受到了消息{1}：{2}", DateTime.Now, b.Receives, b.Messager);
	b.AcceptSocket.Write(b.Messager);
};
server.Accepted += (a, b) => {
	Console.WriteLine("{0} 新连接：{1}", DateTime.Now, b.Accepts);
};
server.Closed += (a, b) => {
	Console.WriteLine("{0} 关闭了连接：{1}", DateTime.Now, b.AcceptSocketId);
};
server.Error += (a, b) => {
	Console.WriteLine("{0} 发生错误({1})：{2}", DateTime.Now, b.Errors, 
		b.Exception.Message + b.Exception.StackTrace);
};
server.Start();
Console.ReadKey();
```

# 服务端(异步)，理论上性能最强

```csharp
var server = new ServerSocketAsync(19990); //监听0.0.0.0:19990
server.Receive += (a, b) => {
	Console.WriteLine("{0} 接受到了消息{1}：{2}", DateTime.Now, b.Receives, b.Messager);
	b.AcceptSocket.Write(b.Messager);
};
server.Accepted += (a, b) => {
	Console.WriteLine("{0} 新连接：{1}", DateTime.Now, b.Accepts);
};
server.Closed += (a, b) => {
	Console.WriteLine("{0} 关闭了连接：{1}", DateTime.Now, b.AcceptSocketId);
};
server.Error += (a, b) => {
	Console.WriteLine("{0} 发生错误({1})：{2}", DateTime.Now, b.Errors, 
		b.Exception.Message + b.Exception.StackTrace);
};
server.Start();
Console.ReadKey();
```

# 客户端

```csharp
var client = new ClientSocket();
client.Error += (sender, e) => {
	Console.WriteLine("[" + DateTime.Now.ToString("MM-dd HH:mm:ss") + "] " 
		+ e.Exception.Message + e.Exception.StackTrace);
};
client.Receive += (sender, e) => {
	switch (e.Messager.Action) {
	}
};
client.Connect("localhost", 19990);

SocketMessager messager = new SocketMessager("GetDatabases", 1);
object dbs = null;
//以下代码等于同步，直到服务端响应(会执行委托)或超时
client.Write(messager, (sender2, e2) => {
	//服务端正常响应会执行这里
	dbs = e2.Messager;
});
Console.WriteLine(dbs);
Console.WriteLine("sldkjglsjdglksdg");
//若不传递第二个委托参数，线程不会等待结果，服务端响应后由 client.Receive 处理
//Console.ReadKey();
client.Close();
```<file_sep>/LinuxCmd.Net.NetWork.Test/Program.cs
﻿using System;

namespace LinuxCmd.Net.NetWork.Test
{
    class Program
    {
        static void Main(string[] args)
        {
            NetWorker net = new NetWorker();
            net.Start();
            Console.ReadLine();
        }
    }
}
<file_sep>/README.md
# LinuxCmd.Net
.net core linux cmd helper.
1. Running Linux CMD.
2. Get linux server status, include CPU, memory, and networking.

## Example

```C#
//redirect:true 获取服务器命令执行结果
var ls = "ls".LinuxBash().Output;

//redirect:false 将命令执行结果重定向输出到服务器
ls = "ls".LinuxBash(false).Output;

//服务器状态对象
LinuxServerInfo server = new LinuxServerInfo();

//系统信息
var OSName = server.OSName;
$"echo {OSName}".LinuxBash(false);

//运行时长
var RunTime = server.RunTime;
$"echo {RunTime}".LinuxBash(false);

//系统负载
var LoadAverages = server.LoadAverages;
$"echo {LoadAverages}".LinuxBash(false);

//CPU状态: cpu描述,cpu核心数,cpu使用率
var cpuInfo = server.Cpu;
$"echo {cpuInfo.SerializeJSON().Replace('(',' ').Replace(')',' ')}".LinuxBash(false);

//内存状态:内存总容量,实际可用容量,已使用的容量,缓存化的容量,系统缓冲容量
var Mem = server.Mem;
$"echo {Mem.SerializeJSON()}".LinuxBash(false);

//磁盘状态:磁盘总容量,已用容量,可用容量,已用百分比
var Disk = server.Disk;
$"echo {Disk.SerializeJSON()}".LinuxBash(false);

//IO读写状态:读请求数量,写请求数量,读字节数,写字节数
var IO = server.IO;
$"echo {IO.SerializeJSON()}".LinuxBash(false);

//网络状态:接收的数据包数量,发送的数据包数量,接收字节数,发送字节数
var NetWork = server.NetWork;
$"echo {NetWork.SerializeJSON()}".LinuxBash(false);

//网络连接状态: tcp客户端IP,服务器IP,连接状态
var NetworkConnections = server.NetworkConnections;
foreach (var net in NetworkConnections)
{
    $"echo {net.SerializeJSON()}".LinuxBash(false);
}

//进程列表:进程id,进程所有者的用户名,虚拟内存使用量,物理内存使用量,进程状态,CPU使用率,进程命令名
var Tasks = server.Tasks;
for (int i = 0; i < 6; i++)
{
    $"echo {Tasks[i].SerializeJSON()}".LinuxBash(false);
}
```<file_sep>/LinuxCmd.Net/Commads/Top.cs
﻿using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.RegularExpressions;
using LinuxCmd.Net.Models;

namespace LinuxCmd.Net.Commads
{
    /// <summary>
    /// top version 3.3.10
    /// </summary>
    public class Top
    {
        public virtual LinuxTopInfo GetTop(string input)
        {
            var rows = input.Split('\n');
            if (rows.Length < 5)
                return null;

            LinuxTopInfo info=new LinuxTopInfo();

            //统计时间,服务器负载
            var stas = rows[0];
            info.Time = Utility.GetSingleByRgx(stas, @"top\s+-\s+(\S+)\s+up");
            info.Days = Convert.ToInt32(Utility.GetSingleByRgx(stas, @"(\d+)\s+days"));
            info.Users = Convert.ToInt32(Utility.GetSingleByRgx(stas, @"(\d+)\s+user"));
            info.Averages = $"{Utility.GetSingleByRgx(stas, @":\s+(\d+\.\d\d),")},{Utility.GetSingleByRgx(stas, @",\s+(\d+\.\d\d),")},{Utility.GetSingleByRgx(stas, @",\s+(\d+\.\d\d)")}";
            
            //进程统计
            var tasks = rows[1];
            info.TaskTotal = Convert.ToInt32(Utility.GetSingleByRgx(tasks, @"(\d+)\s+total"));
            info.RunningCount = Convert.ToInt32(Utility.GetSingleByRgx(tasks, @"(\d+)\s+running"));
            info.SleepingCount = Convert.ToInt32(Utility.GetSingleByRgx(tasks, @"(\d+)\s+sleeping"));
            info.StoppedCount = Convert.ToInt32(Utility.GetSingleByRgx(tasks, @"(\d+)\s+stopped"));
            info.ZombieCount = Convert.ToInt32(Utility.GetSingleByRgx(tasks, @"(\d+)\s+zombie"));

            //cpu数值
            var cpus = rows[2];
            info.UserCpu = Convert.ToDouble(Utility.GetSingleByRgx(cpus, @"(\d+\.\d+)\s+us"));
            info.SystemCpu = Convert.ToDouble(Utility.GetSingleByRgx(cpus, @"(\d+\.\d+)\s+sy"));
            info.NiCpu = Convert.ToDouble(Utility.GetSingleByRgx(cpus, @"(\d+\.\d+)\s+ni"));
            info.FreeCpu = Convert.ToDouble(Utility.GetSingleByRgx(cpus, @"(\d+\.\d+)\s+id"));
            info.WaitCpu = Convert.ToDouble(Utility.GetSingleByRgx(cpus, @"(\d+\.\d+)\s+wa"));
            var hi = Utility.GetSingleByRgx(cpus, @"(\d+\.\d+)\s+hi");
            var si = Utility.GetSingleByRgx(cpus, @"(\d+\.\d+)\s+si");
            var st = Utility.GetSingleByRgx(cpus, @"(\d+\.\d+)\s+st");

            //内存数值
            var mems = rows[3];
            info.MemTotal = Convert.ToDouble(Utility.GetSingleByRgx(mems, @"(\d+)\s+total")) / 1024;
            info.MemFree = Convert.ToDouble(Utility.GetSingleByRgx(mems, @"(\d+)\s+free")) / 1024;
            info.MemUsed = Convert.ToDouble(Utility.GetSingleByRgx(mems, @"(\d+)\s+used")) / 1024;
            info.MemCache = Convert.ToDouble(Utility.GetSingleByRgx(mems, @"(\d+)\s+buff/cache")) / 1024;

            //虚拟内存数值
            var swap = rows[4];
            info.SwapTotal = Convert.ToDouble(Utility.GetSingleByRgx(swap, @"(\d+)\s+total")) / 1024;
            info.SwapFree = Convert.ToDouble(Utility.GetSingleByRgx(swap, @"(\d+)\s+free")) / 1024;
            info.SwapUsed = Convert.ToDouble(Utility.GetSingleByRgx(swap, @"(\d+)\s+used")) / 1024;
            info.SwapCache = Convert.ToDouble(Utility.GetSingleByRgx(swap, @"(\d+)\s+avail")) / 1024;
            info.TaskDetails= GetTaskDetailsByRgx(input);
            return info;
        }

        

        public virtual List<LinuxTopInfo_TaskDetail> GetTaskDetailsByRgx(string input)
        {
            List<LinuxTopInfo_TaskDetail> details= new List<LinuxTopInfo_TaskDetail>();
            var matchs = Regex.Matches(input, @"\s+(\d+)\s+(\S+)\s+\d+\s+\d+\s+(\d+)\s+(\d+)\s+(\d+)\s+(\w+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s*");
            foreach (Match match in matchs)
            {
                if (match.Success)
                {
                    var detail = new LinuxTopInfo_TaskDetail();
                    detail.Pid = match.Groups[1].Value;
                    detail.User = match.Groups[2].Value;
                    detail.Virt = Convert.ToDouble(match.Groups[3].Value) / 1024;
                    detail.Res = Convert.ToDouble(match.Groups[4].Value) / 1024;
                    detail.Shr = Convert.ToDouble(match.Groups[5].Value) / 1024;
                    detail.Status = match.Groups[6].Value;
                    detail.Cpu = Convert.ToDouble(match.Groups[7].Value);
                    detail.Mem = Convert.ToDouble(match.Groups[8].Value);
                    detail.Time = match.Groups[9].Value;
                    detail.Commad = match.Groups[10].Value;
                    details.Add(detail);
                }
            }
            return details;
        }
    }
}
<file_sep>/LinuxCmd.Net/LinuxServerInfo.cs
﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Design;
using System.IO;
using System.Text.RegularExpressions;
using LinuxCmd.Net.Commads;
using LinuxCmd.Net.Models;

namespace LinuxCmd.Net
{
    public class LinuxServerInfo
    {
        /// <summary>
        /// 操作系统信息
        /// </summary>
        public string OSName => GetOSName();
        /// <summary>
        /// 累积运行时间
        /// </summary>
        public string RunTime => GetRunTime();
        /// <summary>
        /// 系统负载,任务队列的平均长度
        /// </summary>
        public string LoadAverages => GetLoadAverages();
        /// <summary>
        /// cpu信息
        /// </summary>
        public CpuInfo Cpu => GetCpu();
        /// <summary>
        /// 内存信息
        /// </summary>
        public MemInfo Mem => GetMem();
        /// <summary>
        /// 磁盘信息
        /// </summary>
        public LinuxDfInfo Disk => LinuxHelper.LinuxDisk();
        /// <summary>
        /// 磁盘IO读写信息
        /// </summary>
        public IOInfo IO => GetIO();
        /// <summary>
        /// 网络信息
        /// </summary>
        public LinuxSarInfo NetWork => LinuxHelper.LinuxSar();
        /// <summary>
        /// 进程列表信息
        /// </summary>
        public List<LinuxTopInfo_TaskDetail> Tasks => GetTasks();
        /// <summary>
        /// 网络连接列表信息
        /// </summary>
        public List<LinuxNetstatInfo> NetworkConnections => LinuxHelper.LinuxNetstats();

        private Top top =new Top();
        #region Realize

        protected virtual string GetOSName()
        {
            var os = Utility.GetSingleByRgx("lsb_release -a".LinuxBash().Output, @"Description:\s+(\S+\s+\S+\s+\S+\s+\S+)");
            if (string.IsNullOrEmpty(os))
                return "NaN";
            return os;
        }
        protected virtual string GetRunTime()
        {
            var text = Utility.GetSingleByRgx("top -b -n 1".LinuxBash().Output, @"up\s+(\d+\s+days,\s+\d+:\d+),");
            if (string.IsNullOrEmpty(text))
                return "NaN";
            var days = Utility.GetSingleByRgx(text, @"(\d+)\s+days,");
            var hours = Utility.GetSingleByRgx(text, @",\s+(\d+):");
            var minutes = Utility.GetSingleByRgx(text, @"\d+:(\d+)");
            return $"{days}天 {hours}小时 {minutes}分钟";
        }
        protected virtual string GetLoadAverages()
        {
            var aver = Utility.GetSingleByRgx("top -b -n 1".LinuxBash().Output, @"load\s+average:\s+(.+)\n");
            if (string.IsNullOrEmpty(aver))
                return "NaN";
            else
                return aver.Replace(" ", "");
        }
        protected virtual CpuInfo GetCpu()
        {
            CpuInfo info = new CpuInfo();

            var cores = Utility.GetSingleByRgx("cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c".LinuxBash().Output, @"(\d+)\s+");
            if (string.IsNullOrEmpty(cores))
                info.CpuCores = -1;
            else
                info.CpuCores = Convert.ToInt32(cores);

            var cpuName = Utility.GetSingleByRgx("cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c".LinuxBash().Output, @"\d+\s+(\S+.+)");
            if (string.IsNullOrEmpty(cpuName))
                info.CpuName = "NaN";
            else
                info.CpuName = cpuName;

            var cpuUsage = Utility.GetSingleByRgx("top -b -n 1".LinuxBash().Output, @"ni,\s*(\S+)\s+id,");
            if (string.IsNullOrEmpty(cpuUsage))
                info.CpuUsage = -1;
            else
            {
                info.CpuUsage = (100 - Convert.ToDouble(cpuUsage)).MathRound();
            }

            return info;
        }
        protected virtual MemInfo GetMem()
        {
            MemInfo info = new MemInfo();

            var total = Utility.GetSingleByRgx("cat /proc/meminfo |grep MemTotal".LinuxBash().Output, @"MemTotal:\s+(\d+)\s+kB");
            if (string.IsNullOrEmpty(total))
                info.MemTotal = -1;
            else
                info.MemTotal = Convert.ToInt32(total) / 1024;

            var available = Utility.GetSingleByRgx("cat /proc/meminfo |grep MemAvailable".LinuxBash().Output, @"MemAvailable:\s+(\d+)\s+kB");
            if (string.IsNullOrEmpty(available))
                info.MemAvailable = -1;
            else
                info.MemAvailable = Convert.ToInt32(available) / 1024;

            var used = Utility.GetSingleByRgx("free -m".LinuxBash().Output, @"Mem:\s+\S+\s+(\S+)\s+");
            if (string.IsNullOrEmpty(used))
                info.MemUsed = -1;
            else
                info.MemUsed = Convert.ToInt32(used);

            var cached = Utility.GetSingleByRgx("cat /proc/meminfo |grep Cached".LinuxBash().Output, @"Cached:\s+(\d+)\s+kB");
            if (string.IsNullOrWhiteSpace(cached))
                info.MemCached = -1;
            else
                info.MemCached = Convert.ToInt32(cached) / 1024;

            var buffers = Utility.GetSingleByRgx("cat /proc/meminfo |grep Buffers".LinuxBash().Output, @"Buffers:\s+(\d+)\s+kB");
            if (string.IsNullOrEmpty(buffers))
                info.MemBuffers = -1;
            else
                info.MemBuffers = Convert.ToInt32(buffers) / 1024;

            info.MemUsage = (100 - Convert.ToDouble((info.MemAvailable * 1.00) / (info.MemTotal * 1.00) * 100)).MathRound();

            return info;
        }
        protected virtual IOInfo GetIO()
        {
            IOInfo info = new IOInfo();
            var result = "sar -b 1 1".LinuxBash().Output;
            if (string.IsNullOrWhiteSpace(result))
                return info;
            Match match = Regex.Match(result, @"Average:\s+\S+\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)");
            if (match.Success)
            {
                info.ReadCount = Convert.ToDouble(match.Groups[1].Value).MathRound();
                info.WriteCount = Convert.ToDouble(match.Groups[2].Value).MathRound();
                info.ReadBytes = Convert.ToDouble(match.Groups[3].Value).MathRound();
                info.WriteBytes = Convert.ToDouble(match.Groups[4].Value).MathRound();
            }
            return info;
        }

        protected virtual List<LinuxTopInfo_TaskDetail> GetTasks()
        {
            return top.GetTaskDetailsByRgx("top -b -n 1".LinuxBash().Output);
        }

        #endregion

    }

    public class CpuInfo
    {
        /// <summary>
        /// cpu描述
        /// </summary>
        public string CpuName { get; set; }
        /// <summary>
        /// cpu核心数
        /// </summary>
        public int CpuCores { get; set; }
        /// <summary>
        /// cpu使用率
        /// </summary>
        public double CpuUsage { get; set; }
    }

    public class MemInfo
    {
        /// <summary>
        /// 内存总容量
        /// </summary>
        public int MemTotal { get; set; }
        /// <summary>
        /// 实际可用内存 MB
        /// </summary>
        public int MemAvailable { get; set; }
        /// <summary>
        /// 已使用的内存 MB
        /// </summary>
        public int MemUsed { get; set; }
        /// <summary>
        /// 缓存化的内存 MB
        /// </summary>
        public int MemCached { get; set; }
        /// <summary>
        /// 系统缓冲 MB
        /// </summary>
        public int MemBuffers { get; set; }
        /// <summary>
        /// 内存相对使用率
        /// </summary>
        public double MemUsage { get; set; }
    }

    public class IOInfo
    {
        public double ReadCount { get; set; }
        public double WriteCount { get; set; }
        public double ReadBytes { get; set; }
        public double WriteBytes { get; set; }
    }
}<file_sep>/LinuxCmd.Net.NetWork/ClientHandler.cs
﻿using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using Cowboy.Sockets.Core;

namespace LinuxCmd.Net.NetWork
{
    public class ClientHandler
    {
        public string Ip { get; private set; }
        public int? Port { get; private set; }
        public int? ReconnectionCount { get; private set; }
        public int? TimeOut { get; private set; }
        public int? Polling { get; private set; }
        public int Reconnectioned { get; private set; }
        public System.Threading.Timer PollingTimer { get; private set; }
        public TcpSocketClient Client;
        public bool downTag = false;
        public ClientHandler()
        {
            LoadConfig();
        }

        public void Start()
        {
            LogHelper.Logger.Information("Client Start...");
            CreateTcpClient();
            PollingTimer = new System.Threading.Timer(Heartbeat, this, Polling.Value * 1000, Polling.Value * 1000);
        }

        private void LoadConfig()
        {
            ConfigHander.configuration.Reload();
            this.Ip = ConfigHander.GetString("master:ip");
            this.Port = ConfigHander.GetInt("master:port");
            this.ReconnectionCount = ConfigHander.GetInt("worker:reconnection");
            this.TimeOut = ConfigHander.GetInt("worker:timeout");
            this.Polling = ConfigHander.GetInt("worker:polling");
        }

        private void CreateTcpClient()
        {
            if (string.IsNullOrEmpty(Ip) || !Port.HasValue)
            {
                LogHelper.Logger.Error("ip,port is not available !!!");
                throw new Exception("ip,port is not available !!");
            }

            var config = new TcpSocketClientConfiguration();
            IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse(Ip), Port.Value);

            Client = new TcpSocketClient(ipEndPoint, config);
            Client.ServerConnected += ServerConnected;
            Client.ServerDisconnected += ServerDisconnected;
            Client.ServerDataReceived += ServerDataReceived;
            Client.Connect();
        }
        private void Heartbeat(object obj)
        {
            try
            {
                if (Reconnectioned >= ReconnectionCount)
                {
                    //重连熔断降级至24小时一次轮询
                    if (!downTag)
                    {
                        LogHelper.Logger.Error($"{ReconnectionCount}次重连失败,降级轮询频率至24小时一次");
                        PollingTimer.Change(24 * 60 * 60 * 1000, 24 * 60 * 60 * 1000);
                    }

                    return;
                }

                if (Client == null)
                    CreateTcpClient();
                if (Client.State == TcpSocketConnectionState.Connected)
                {
                    Client.Send(Encoding.UTF8.GetBytes(CommandHandler.HeartBeatCmd()));
                    Reconnectioned = 0;
                    //恢复轮询正常状态
                    downTag = true;
                    PollingTimer.Change(Polling.Value * 1000, Polling.Value * 1000);
                }
                else
                {
                    Reconnectioned++;
                }
            }
            catch (Exception ex)
            {
                LogHelper.Logger.Error($"Heartbeat Error:"+ex.Message+ex.StackTrace);
            }
        }

        private void ServerConnected(object sender, TcpServerConnectedEventArgs e)
        {
            Console.WriteLine($"服务器 {e.RemoteEndPoint} 已连接.");
        }

        private void ServerDisconnected(object sender, TcpServerDisconnectedEventArgs e)
        {
            Console.WriteLine($"服务器 {e.RemoteEndPoint} 断开连接.");
        }

        private void ServerDataReceived(object sender, TcpServerDataReceivedEventArgs e)
        {
            var text = Encoding.UTF8.GetString(e.Data, e.DataOffset, e.DataLength);
            Console.Write($"服务器 : {e.Client.RemoteEndPoint} --> ");
            if (e.DataLength < 256)
            {
                Console.WriteLine(text);
            }
            else
            {
                Console.WriteLine("{0} Bytes", e.DataLength);
            }
        }

        public void Dispose()
        {
            Client.Close();
            Client.Dispose();
            Client = null;
            PollingTimer.Dispose();
            PollingTimer = null;
        }
    }
}<file_sep>/LinuxCmd.Net.NetWork/ConfigHander.cs
﻿using System;
using Microsoft.Extensions.Configuration;

namespace LinuxCmd.Net.NetWork
{
    public class ConfigHander
    {
        public static IConfigurationRoot configuration = new ConfigurationBuilder()
            .SetBasePath(AppContext.BaseDirectory)
            .AddJsonFile("app.json")
            .Build();

        public static string GetString(string key)
        {
            return configuration[key];
        }

        public static int GetInt(string key)
        {
            return Convert.ToInt32(configuration[key]);
        }
    }
}<file_sep>/LinuxCmd.Net/Models/LinuxNetstatInfo.cs
﻿namespace LinuxCmd.Net.Models
{
    public class LinuxNetstatInfo
    {
        public string Proto { get; set; }
        public string LocalAddress { get; set; }
        public string ForeignAddress { get; set; }
        public string State { get; set; }
        public string ProgramName { get; set; }
    }
}<file_sep>/LinuxCmd.Net/Commads/Df.cs
﻿using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using LinuxCmd.Net.Models;

namespace LinuxCmd.Net.Commads
{
    public class Df
    {
        public virtual List<LinuxDfInfo> GetDfInfos(string input)
        {
            var matchs = Regex.Matches(input, @"\s*(\S+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\S+)%\s+(\S+)");
            List<LinuxDfInfo> list = new List<LinuxDfInfo>();
            foreach (Match match in matchs)
            {
                if (match.Success)
                {
                    LinuxDfInfo info = new LinuxDfInfo();
                    info.Filesystem = match.Groups[1].Value;
                    info.Size = Convert.ToDouble(match.Groups[2].Value) /1024;
                    info.Used = Convert.ToDouble(match.Groups[3].Value) / 1024;
                    info.Avail = Convert.ToDouble(match.Groups[4].Value) / 1024;
                    info.UseUsage = Convert.ToDouble(match.Groups[5].Value);
                    info.Mounted = match.Groups[6].Value;
                    list.Add(info);
                }
            }
            return list;
        }

        public virtual LinuxDfInfo GetDiskInfo(string input)
        {
            return GetDfInfos(input)[0];
        }
    }
}<file_sep>/LinuxCmd.Net/Utility.cs
﻿using System;
using System.Text.RegularExpressions;

namespace LinuxCmd.Net
{
    public static class Utility
    {
        public static string GetSingleByRgx(string input, string pattern)
        {
            if (string.IsNullOrWhiteSpace(input))
                return "";
            var match = Regex.Match(input, pattern);
            return match.Success ? match.Groups[1].Value : "";
        }

        public static double MathRound(this double d)
        {
            return Math.Round(d, 1);
        }
    }
}<file_sep>/LinuxCmd.Net.ControlDesk/MainForm.cs
﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using LinuxCmd.Net.NetWork;

namespace LinuxCmd.Net.ControlDesk
{
    public partial class MainForm : Form
    {
        private NetWorker net;
        public MainForm()
        {
            InitializeComponent();
            net = new NetWorker();
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            net.Start();
        }
    }
}
<file_sep>/LinuxCmd.Net/LinuxHelper.cs
﻿using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using LinuxCmd.Net.Commads;
using LinuxCmd.Net.Models;

namespace LinuxCmd.Net
{
    public static class LinuxHelper
    {
        public static BashResult LinuxBash(this string cmd,bool redirect = true)
        {
            if (!RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
                return new BashResult() { Error = "The current system does not support it!", Success = false, Output = null };
            var args = cmd.Replace("\"", "\\\"");
            var startInfo = new ProcessStartInfo
            {
                FileName = "/bin/bash",
                Arguments = $"-c \"{args}\"",
                RedirectStandardOutput = redirect,
                RedirectStandardError = redirect,
                UseShellExecute = false,
                CreateNoWindow = true,
                ErrorDialog = false
            };

            using (var process = new Process() {StartInfo = startInfo})
            {
                process.Start();
                string result = redirect ? process.StandardOutput.ReadToEnd() : "";
                string error = redirect ? process.StandardError.ReadToEnd() : "";
                process.WaitForExit();
                int code = process.ExitCode;
                process.Close();
                return new BashResult() {Success = (code == 0), Error = error, Output = result};
            }
        }

        public static LinuxTopInfo LinuxTop()
        {
            var result = "top -b -n 1".LinuxBash();
            return result.Success ? (new Top()).GetTop(result.Output) : null;
        }

        public static LinuxDfInfo LinuxDisk()
        {
            var result = "df".LinuxBash();
            return result.Success ? (new Df()).GetDiskInfo(result.Output) : null;
        }

        public static LinuxVmstatInfo LinuxVmstat()
        {
            var result = "vmstat".LinuxBash();
            return result.Success ? (new Vmstat()).GetLinuxVmstatInfo(result.Output) : null;
        }

        public static LinuxSarInfo LinuxSar()
        {
            var result = "sar -n DEV 1 1".LinuxBash();
            return result.Success ? (new Sar()).GetLinuxSarInfo(result.Output) : null;
        }

        public static List<LinuxNetstatInfo> LinuxNetstats()
        {
            var result = "netstat -lntup".LinuxBash();
            return result.Success ? (new Netstat()).GetLinuxNetstatInfos(result.Output) : null;
        }
    }
}