Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
namespace rBits
{
internal static class Program
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new Service1()
};
ServiceBase.Run(ServicesToRun);
}
}
}
Service1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
using Notify;
using Notify.Log;
namespace rBits
{
public partial class Service1 : ServiceBase
{
private TcpServer rBits;
private NtLog log = new NtLog();
public Service1()
{
InitializeComponent();
rBits = new TcpServer("127.0.0.1", 8421);
//订阅事件
rBits.LogReady += log.OnLogging;
}
protected override void OnStart(string[] args)
{
string path = AppDomain.CurrentDomain.BaseDirectory;
path += "\\VerCtrl.Cfg.json";
rBits.ReadCtrlVersionCfg(path);
rBits.Startup();
}
protected override void OnStop()
{
rBits.Stop();
}
}
}
ProjectInstall.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration.Install;
using System.Linq;
using System.Threading.Tasks;
namespace rBits
{
[RunInstaller(true)]
public partial class ProjectInstaller : System.Configuration.Install.Installer
{
public ProjectInstaller()
{
InitializeComponent();
}
}
}
Libraries.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Net.Http.Headers;
using System.Net.Http;
using System.Xml.Linq;
using System.IO;
using System.Diagnostics;
using System.Net.Mail;
using System.Net.Configuration;
using System.Reflection;
using System.IO.Compression;
//不常用的库
//using Microsoft.Data.Sqlite;
//以下是第三方库,从NuGet里导入
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using SQLitePCL;
using Microsoft.Data.Sqlite;
using MimeKit;
//using MailKit.Net.Smtp;
//using MailKit.Security;
//以下是自定义命名空间
using Notify;
using Notify.Log;
using Notify.App;
using Notify.App.Cpolar;
//using Notify.Cploar;
//using bRedBit;
//项目依赖项
/* Newtonsoft.Json.dll
* verctrlcfg.json
*
* */
namespace Notify
{
class CtrlVersion
{
public ushort min { get; set; }
public ushort max { get; set; }
public CtrlVersion()
{
min = 498;
max = 506;
}
public CtrlVersion(ushort min, ushort max)
{
this.min = min;
this.max = max;
}
}
class NotNtFlagException : Exception
{
public NotNtFlagException(string message) : base(message) { }
}
class NtVersionCtrlException : Exception
{
public NtVersionCtrlException(string message) : base(message) { }
}
static class Nt
{
static public bool CheckFlag(ref byte[] msg)
{
//"N" 78 0x4E
//"t"116 0x74
if (msg != null && msg[0] == 0x4E && msg[1] == 0x74)
{
return true;
}
return false;
}
/// <summary>
/// 检查消息的前4个字节,检查Flag和版本号
/// </summary>
/// <param name="msg">接收的数据,消息</param>
/// <param name="verctrlcfg">版本控制配置文件</param>
/// <returns>Flag和Version都没问题就返回true,否则返回false</returns>
static public bool CheckFlagVersion(ref byte[] msg, string verctrlcfg)
{
var ctrlver = ReadConfig(verctrlcfg);
if (CheckFlag(ref msg) == true && CtrlVersion(ref msg, ctrlver.min, ctrlver.max) == true)
return true;
return false;
}
static public uint CheckFlagVerCmdno(ref byte[] msg, string verctrlcfg)
{
if (CheckFlag(ref msg) == false)
{
throw new NotNtFlagException("NotNtFlag CheckFlag false");
}
var ctrlver = ReadConfig(verctrlcfg);
if (CtrlVersion(ref msg, ctrlver.min, ctrlver.max) == false)
{
throw new NtVersionCtrlException("客户端版本不在控制的范围内");
}
return GetCmdNo(ref msg);
}
static public ushort GetVersion(ref byte[] msg)
{
return (ushort)((msg[2] << 8) + msg[3]);
}
static public bool CtrlVersion(ref byte[] msg, ushort min = 498, ushort max = 503)
{
ushort ver = (ushort)((msg[2] << 8) + msg[3]);
//Console.WriteLine($"{ver},{msg[2]},{msg[3]}");
if (ver >= min && ver <= max)
{
return true;
}
return false;
}
static public bool CtrlVersion(ref byte[] msg, string verctrlcfg)
{
var ctrlver = ReadConfig(verctrlcfg);
ushort ver = (ushort)((msg[2] << 8) + msg[3]);
//Console.WriteLine($"{ver},{msg[2]},{msg[3]}");
if (ver >= ctrlver.min && ver <= ctrlver.max)
{
return true;
}
return false;
}
static public uint GetCmdNo(ref byte[] msg)
{
uint CmdNo = (uint)((msg[4] << 24) + (msg[5] << 16) + (msg[6] << 8) + msg[7]);
return CmdNo;
}
static public CtrlVersion ReadConfig(string cfg = "verctrlcfg.json")
{
try
{
// 读取文件内容
string jsonContent = File.ReadAllText(cfg); //File.ReadAllText这个操作是阻塞的,并且比较费时。
// 反序列化JSON字符串到对象
CtrlVersion vers = JsonConvert.DeserializeObject<CtrlVersion>(jsonContent);
// 输出结果
//Console.WriteLine($"{vers.min} >= ver >= {vers.max}");
return vers;
}
catch (Exception e)
{
throw e;
}
}
}
class TcpServer
{
private TcpListener tcpListener;
private Thread listenThread;
private volatile bool runing = false;
private List<TcpClient> clients = new List<TcpClient>();
private volatile bool IsWritingLog = false;//只能有一个线程写,不能多个线程同时写。
//private int aliveclients = 5;//这个要大约等于3,也就是至少要保留3个线程
private CtrlVersion VerCtrl = new CtrlVersion();
//private ulong totalAccess = 0;
private List<LogContent> logBuffer = new List<LogContent>();
private readonly SynchronizationContext _synchronizationContext = SynchronizationContext.Current;//跨线程需要同步上下文
public int ClientsCount { get { return clients.Count; } }
/// <summary>
/// 阶段性访问量,一读就清空。
/// </summary>
//public ulong TotalAccess
//{
// get
// {
// var temp = this.totalAccess;
// this.totalAccess = 0;
// return temp;
// }
//}
/// <summary>
/// 日志缓存器,这个属性读后就清空了。
/// </summary>
public List<LogContent> LogBuf
{
get //深拷贝,防止并发环境里的遗漏
{
List<LogContent> temp = new List<LogContent>();
//在 C# 中,使用 foreach 循环遍历集合时,如果集合在遍历过程中被修改(如添加、删除元素),就会抛出此异常System.InvalidOperationException。
foreach (LogContent content in this.logBuffer)
{
temp.Add(content);
}
foreach (LogContent content in temp)
{
this.logBuffer.Remove(content);
}
return temp;
}
}
public int LogBufferCount { get { return this.logBuffer.Count; } }
// 定义一个委托
public delegate void LogReadyHandler(List<LogContent> logs);
// 定义一个事件
public event LogReadyHandler LogReady;
// 模拟数据生产
private void LogTrigger()
{
//#if DEBUG
// TempLog.logging($"{this.LogBufferCount}");
//#endif
//SynchronizationContext _synchronizationContext = SynchronizationContext.Current;//跨线程需要同步上下文
//_synchronizationContext = SynchronizationContext.Current;
// 触发事件
if (this.LogBufferCount > 0)
{
//#if DEBUG
// TempLog.logging($"{this.LogBufferCount}触发日志缓存和写入{this.LogReady.ToString()}");
//#endif
//LogReady?.Invoke(this.LogBuf);//读数据并清空了日志缓存
if (_synchronizationContext != null)
{
_synchronizationContext.Send(state =>
{
try
{
LogReady?.Invoke(this.LogBuf); // 如果有任何订阅者,调用他们的方法
}
catch (Exception ex)
{
//Console.WriteLine($"Exception during event invocation: {ex.Message}");
#if DEBUG
TempLog.logging($"{this.LogBufferCount}触发日志缓存和写入{this.LogReady.ToString()} {ex.ToString()}");
#endif
}
}, null);
}
else
{
try
{
LogReady?.Invoke(this.LogBuf); // 如果有任何订阅者,调用他们的方法
}
catch (Exception ex)
{
//Console.WriteLine($"Exception during event invocation: {ex.Message}");
#if DEBUG
TempLog.logging($"{this.LogBufferCount} Context==null {this.LogReady.ToString()} {ex.ToString()}");
#endif
}
}
}
}
public TcpServer(string ipAddress, int port)
{
this.tcpListener = new TcpListener(IPAddress.Parse(ipAddress), port);
if (clients == null)
clients = new List<TcpClient>();
}
public void Startup()
{
if (this.listenThread == null || this.listenThread.IsAlive == false)
{
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
}
switch (listenThread.ThreadState)
{
case System.Threading.ThreadState.Unstarted:
this.listenThread.Start();
runing = true;
break;
case System.Threading.ThreadState.StopRequested:
case System.Threading.ThreadState.AbortRequested:
case System.Threading.ThreadState.Aborted:
case System.Threading.ThreadState.Stopped:
case System.Threading.ThreadState.Suspended:
case System.Threading.ThreadState.SuspendRequested:
this.listenThread.Abort();
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
this.listenThread.Start();
runing = true;
break;
case System.Threading.ThreadState.Running:
runing = true;
break;
}
if (clients == null)
clients = new List<TcpClient>();
}
public void Startup(string ipaddr, int port)
{
this.tcpListener = new TcpListener(IPAddress.Parse(ipaddr), port);
if (this.listenThread == null || this.listenThread.IsAlive == false)
{
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
}
switch (listenThread.ThreadState)
{
case System.Threading.ThreadState.Unstarted:
this.listenThread.Start();
runing = true;
break;
case System.Threading.ThreadState.StopRequested:
case System.Threading.ThreadState.AbortRequested:
case System.Threading.ThreadState.Aborted:
case System.Threading.ThreadState.Stopped:
case System.Threading.ThreadState.Suspended:
case System.Threading.ThreadState.SuspendRequested:
this.listenThread.Abort();
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
this.listenThread.Start();
runing = true;
break;
case System.Threading.ThreadState.Running:
runing = true;
break;
}
if (clients == null)
clients = new List<TcpClient>();
}
public static bool CheckPortAvali(int port, string ipaddr)
{
TcpListener tcp = new TcpListener(IPAddress.Parse(ipaddr), port);
try
{
tcp.Start();
tcp.Stop();
}
catch (SocketException se)
{
//if(se.ErrorCode==10048)
if (se.ErrorCode == (int)SocketError.AddressAlreadyInUse)
{
return false;
}
}
return true;
}
public void ReadCtrlVersionCfg(string cfg = "verctrlcfg.json")
{
try
{
// 读取文件内容
string jsonContent = File.ReadAllText(cfg); //File.ReadAllText这个操作是阻塞的,并且比较费时。
// 反序列化JSON字符串到对象
CtrlVersion vers = JsonConvert.DeserializeObject<CtrlVersion>(jsonContent);
// 输出结果
//Console.WriteLine($"{vers.min} >= ver >= {vers.max}");
this.VerCtrl = vers;
}
catch (Exception e)
{
throw e;
}
}
/// <summary>
/// 剔除掉Tcp的Accept阻塞,要与runing = false;配合使用
/// </summary>
private void kickAcceptBlock()
{
// 创建一个TcpClient实例并连接到服务器
TcpClient client = new TcpClient();
client.Connect((IPEndPoint)this.tcpListener.LocalEndpoint);
// 关闭连接
client.Close();
client.Dispose();
}
public void Stop()
{
//#if DEBUG
// TempLog.logging($"IsBlocking:{this.tcpListener.Server.Blocking}");
//#endif
runing = false;
if (this.tcpListener.Server.Blocking)
kickAcceptBlock();
//#if DEBUG
// TempLog.logging($"Clients Count:{clients.Count}");
//#endif
foreach (TcpClient client in clients)
{
client.Close();
client.Dispose();
}
clients.Clear();
//#if DEBUG
// TempLog.logging($"Pending:{this.tcpListener.Pending()}");
//#endif
this.tcpListener.Server.Blocking = false; //设为非阻塞模式
//this.listenThread.Join();//Stop其他线程,本线程会运行,但是会阻塞程序和界面。
//Console.WriteLine("Stop");
this.tcpListener.Stop();//先调用Stop方法,Socket会报错。
//System.Net.Sockets.SocketException (0x80004005): 一个封锁操作被对 WSACancelBlockingCall 的调用中断。
this.listenThread.Abort();
System.GC.Collect();
}
private void ListenForClients()
{
TcpClient client = new TcpClient();
this.tcpListener.Start();
//#if DEBUG
// TempLog.logging($"TcpServierIsRuning:{this.runing}");
//#endif
Task.Run(() =>
{
try
{
while (this.runing)
{
// 阻塞直到客户端连接
client = this.tcpListener.AcceptTcpClient(); //关闭的时候可能会发生异常
//this.totalAccess++; //统计接访客户端数量
// 创建一个新的线程来处理客户端通信
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.IsBackground = true; //后台线程不阻塞主线程,后台线程用完后自动退出
clientThread.Start(client);
//剔除休眠客户端
for (int i = 0; (i < clients.Count); i++) // && (clients.Count >= this.aliveclients)
{
bool IsConnectedR = false, IsConnectedW = false, IsConnectedE = false;
if (clients[i].Available != 0 && clients[i].Client.Poll(6000, SelectMode.SelectRead))
IsConnectedR = true;//isConnected
if (clients[i].Client.Poll(6000, SelectMode.SelectWrite))
IsConnectedW = true;
if (clients[i].Client.Poll(6000, SelectMode.SelectError) == false)
IsConnectedE = true;
if (!(IsConnectedR || IsConnectedW) || (IsConnectedE == true))
{
clients[i].Close();
clients[i].Dispose();
clients.RemoveAt(i);
}
if (i >= 5)
GC.Collect();
}
//阻塞问题
if (this.runing == false)
{
clientThread.Abort();
}
//#if DEBUG
// TempLog.logging("NotifyService Into ListenForClients");
//#endif
}
}
catch (ObjectDisposedException ode)
{
this.logBuffer.Add(new LogContent(LogLevel.Critical, ode.Message, ode));
//throw ode;
//return;//Stop时候报错
}
catch (SocketException se)
{
// 确保释放资源
if (client != null)
{
client.Close();
}
if (this.tcpListener != null)
{
this.tcpListener.Stop(); // 如果还没有停止的话
}
this.logBuffer.Add(new LogContent(LogLevel.Fault, se.Message, se));
//throw se;
}
catch (Exception ex)
{
this.logBuffer.Add(new LogContent(LogLevel.Exception, ex.Message, ex));
//throw ex;
}
});
}
/// <summary>
/// 注意接受缓存只有4096字节。
/// </summary>
/// <param name="client">连接进来的客户端</param>
private async void HandleClientComm(object client)
{
this.logBuffer.Add(new LogContent(LogLevel.Statistic, "HandleClientComm"));
TcpClient tcpClient = (TcpClient)client; //注意tcpClient.Close()关闭之后后面就无法接受连接。
NetworkStream clientStream = tcpClient.GetStream();
byte[] message = new byte[4096];
int messagebytes;
while (this.runing)
{
messagebytes = 0;
//接收数据
try
{
// 阻塞直到客户端发送数据
messagebytes = clientStream.Read(message, 0, message.Length);//这里有可能缓冲小了
}
catch (ArgumentOutOfRangeException outrange)//缓存区太小异常
{
this.logBuffer.Add(new LogContent(LogLevel.Error, outrange.Message, outrange));
//return;
clientStream.Close();
goto End;
}
catch (ObjectDisposedException ode) //关闭Client,下一个客户端访问就报这个异常。//这个异常会陷入一个死循环,烧CPU
{
this.logBuffer.Add(new LogContent(LogLevel.Critical, ode.Message, ode));
//return; //NetworkStream Dispose, can not send
clientStream.Close();
goto End;
}
catch (IOException ioe) //多个线程写文件操作就会报这个异常
{
if (ioe.InnerException is SocketException socketEx)
{
switch (socketEx.SocketErrorCode)
{
case SocketError.ConnectionReset:
// 连接被对方重置(可能是客户端关闭)
this.logBuffer.Add(new LogContent(LogLevel.Warning, "连接被对方重置(可能是客户端关闭)", ioe));
break;
case SocketError.ConnectionAborted:
// 连接被对方异常关闭
this.logBuffer.Add(new LogContent(LogLevel.Warning, "连接被对方异常关闭", ioe));
break;
// 处理其他 SocketError 代码
}
}
//return; //NetworkStream Dispose, can not send
goto End;
}
catch (InvalidOperationException ioe) //Socket未启动导致后面的操作无效
{
this.logBuffer.Add(new LogContent(LogLevel.Error, ioe.Message, ioe));
goto End;
}
catch (ArgumentException ae) //参数引发的异常,可能message有问题
{
this.logBuffer.Add(new LogContent(LogLevel.Error, ae.Message, ae));
goto End;
}
catch (Exception e) //其他异常,比如 客户端断开了连接
{
this.logBuffer.Add(new LogContent(LogLevel.Exception, e.Message, e));
goto End;
}
if (messagebytes < 6)
{
this.logBuffer.Add(new LogContent(LogLevel.Mistake, "messagebytes < 6"));
goto End;
}
//检查版本号 改读类的字段了 //每次这里读配置文件比较费时间。可能是因为其他线程占用文件。
if (Nt.CtrlVersion(ref message, this.VerCtrl.min, this.VerCtrl.max) == false)
{
#if DEBUG
TempLog.logging("CheckVersionFalse");
#endif
this.logBuffer.Add(new LogContent(LogLevel.Warning, "来访客户端版本不在受控范围内"));
goto End;
}
//按Falg选择应用框架
switch ((message[0] << 8) | message[1])
{
case (int)SwitchApp.Nt:
goto NtApp;
//break;
case (int)SwitchApp.bRB:
goto End;
//break;
case (int)SwitchApp.ECHO:
goto Turn; //ECHO 回显
//break;
default:
this.logBuffer.Add(new LogContent(LogLevel.Warning, "应用标识Flag不存在"));
goto End;
}
NtApp:
try
{
switch (Nt.GetCmdNo(ref message))
{
case 1://获取Cploar并写缓存
{
//异步
var cpinfos = await DynamicCpolar.GetCpolarInfo();
// 写缓存到文件
CpolarCache cpolarCache = new CpolarCache();
cpolarCache.FurthestUpdate = DynamicCpolar.GetLastUpdateFromCpolarInfp(cpinfos);
cpolarCache.cpolarCache = cpinfos;
var cpjson = JsonConvert.SerializeObject(cpolarCache);
try
{
if (cpjson != null)
File.WriteAllText("./CpolarCache.json.cache", cpjson);//在服务里要用绝对路径
}
catch (Exception ex)
{
#if DEBUG
TempLog.logging(ex.ToString());
#endif
this.logBuffer.Add(new LogContent(LogLevel.Mistake, "写缓存文件错误\"./CpolarCache.json.cache\"", ex));
}
// 将CploarInfo对象序列化成JSON字符串
string jsonString = JsonConvert.SerializeObject(cpinfos);
ASCIIEncoding encod = new ASCIIEncoding();
message = encod.GetBytes(jsonString);
messagebytes = message.Length;
}
break;
case 2:
//读DynamicCpolar缓存文件
{
string jsonStr = string.Empty;
if (File.Exists("./CpolarCache.json.cache"))
{
var cpojson = File.ReadAllText("./CpolarCache.json.cache");
CpolarCache CpolarCache = new CpolarCache();
CpolarCache = JsonConvert.DeserializeObject<CpolarCache>(cpojson);
if (CpolarCache.FurthestUpdate > DateTime.Now.AddHours(-12))
{
// 将CploarInfo对象序列化成JSON字符串
jsonStr = JsonConvert.SerializeObject(CpolarCache.cpolarCache);
ASCIIEncoding encod = new ASCIIEncoding();
message = encod.GetBytes(jsonStr);
messagebytes = message.Length;
}
else
{
goto case 1;
}
}
else
{
goto case 1;
}
}
break;
case 3: //无缓存
{
//异步
var cpinfos = await DynamicCpolar.GetCpolarInfo();
// 将CploarInfo对象序列化成JSON字符串
string jsonString = JsonConvert.SerializeObject(cpinfos);
ASCIIEncoding encod = new ASCIIEncoding();
message = encod.GetBytes(jsonString);
messagebytes = message.Length;
}
break;
}
goto Turn;
}
catch (Exception e)
{
this.logBuffer.Add(new LogContent(LogLevel.Exception, e.Message, e));
goto End;
}
// bRBApp:
// if (bRB.CheckFlagRB(ref message, messagebytes) == true && messagebytes > 4)
// {
// byte key = bRB.GetKey(ref message, messagebytes);
//#if DEBUG
// Console.WriteLine("bRB应用来访");
// Console.WriteLine("key:{0}", key);
//#endif
// byte[] data = new byte[messagebytes - 4];
// for (int i = 0; i < data.Length; i++)
// {
// data[i] = (byte)(message[i + 4] ^ key);
// }
// goto End;
// }
// ;
Turn:
try
{
//#if DEBUG
// TempLog.logging(ASCIIEncoding.ASCII.GetString(message,4,messagebytes));
//#endif
// 发送回显数据给客户端
clientStream.Write(message, 0, messagebytes);
clientStream.Flush();
}
catch (Exception e)
{
this.logBuffer.Add(new LogContent(LogLevel.Exception, e.Message, e));
}
End:
try
{
//this.logBuffer.Add(new LogContent(LogLevel.Debug, "进入日志程序"));
clientStream.Close();//无法访问已释放的对象。对象名:“System.Net.Sockets.NetworkStream”。
tcpClient.Close();//调用此方法最终将导致关联的 Socket 关闭,TcpListener也可能会关闭。
//导出日志
LogTrigger();
}
catch (Exception e) //不处理
{
this.logBuffer.Add(new LogContent(LogLevel.Exception, e.Message, e));
return;
}
return;
}
}
}
}
namespace Notify.Log
{
public enum LogLevel
{
Trace = 0,
Debug = 1,
Information = 2,
Statistic = 3,
Warning = 4,
Mistake = 6, //轻微错误
Exception = 5,
Error = 7, //逻辑错误
Critical = 8, //严重错误
Fault = 9 //致命错误
}
//临时日志是写文本文件,这种操作在高并发程序里会造成程序崩溃
public class TempLog
{
//注意只有一个线程写,不能多个线程同时写文件。
static public void logging(List<NtLog> logbuf, string filepath = "./NotifyLog.log")
{
// 确保日志文件的目录存在
Directory.CreateDirectory(Path.GetDirectoryName(filepath));
// 使用StreamWriter写入日志
using (StreamWriter writer = new StreamWriter(filepath, true)) // true表示追加模式
{
//writer.WriteLine($"Log Entry: {DateTime.Now} - This is a test log entry.");
// 这里可以添加更多的日志写入操作
//foreach (NtLog log in logbuf)
//{
// writer.WriteLine(log.ToString());
// 移除已经写了的缓存
// logbuf.Remove(log);//迭代器安全问题
//}
for (int i = 0; i < logbuf.Count; i++)
{
//#if DEBUG
// Console.WriteLine(logbuf[i].ToString());
//#endif
writer.WriteLine(logbuf[i].ToString());
logbuf.RemoveAt(i);
}
}
}
static public void logging(List<NtLog> logbuf)
{
string fileName = $"{DateTime.Now:yyyy-MM-dd}.log"; // 构建文件名,例如 "2023-04-01.log"
string fullPath = Path.Combine("./logs", fileName);
// 确保日志文件的目录存在
Directory.CreateDirectory(Path.GetDirectoryName(fullPath));
// 使用StreamWriter写入日志
using (StreamWriter writer = new StreamWriter(fullPath, true)) // true表示追加模式
{
//writer.WriteLine($"Log Entry: {DateTime.Now} - This is a test log entry.");
// 这里可以添加更多的日志写入操作
//foreach (NtLog log in logbuf)
//{
// writer.WriteLine(log.ToString());
// 移除已经写了的缓存
// logbuf.Remove(log);//迭代器安全问题
//}
for (int i = 0; i < logbuf.Count; i++)
{
#if DEBUG
Console.WriteLine(logbuf[i].ToString());
#endif
writer.WriteLine(logbuf[i].ToString());
logbuf.RemoveAt(i);
}
}
}
static public void logging(string message, string logpath)
{
using (StreamWriter writer = new StreamWriter(logpath, true)) // true表示追加模式
{
//string fileName = $"{DateTime.Now:yyyy-MM-dd}.log"; // 构建文件名,例如 "2023-04-01.log"
string content = $"{DateTime.Now:yyyy-MM-ddTHH:mm:ss} {message}";
writer.WriteLine(content);
}
}
static public void logging(string message)
{
string path = AppDomain.CurrentDomain.BaseDirectory;
using (StreamWriter writer = new StreamWriter(path + "//TempLog.log", true)) // true表示追加模式
{
//string fileName = $"{DateTime.Now:yyyy-MM-dd}.log"; // 构建文件名,例如 "2023-04-01.log"
string content = $"{DateTime.Now:yyyy-MM-ddTHH:mm:ss} {message}";
writer.WriteLine(content);
}
}
}
public class LogContent
{
public DateTime Occurrence { get; set; }
public LogLevel Level { get; set; }
public StackTrace Trace { get; set; }
public string Message { get; set; }
public LogContent() { }
public LogContent(LogLevel level, string message)
{
this.Occurrence = DateTime.Now;
this.Level = level;
this.Trace = new StackTrace(true);//捕捉当前堆栈
this.Message = message;
}
public LogContent(LogLevel level, string message, Exception e)
{
this.Occurrence = DateTime.Now;
this.Level = level;
this.Trace = new StackTrace(e, true);//捕捉当前异常堆栈堆栈
this.Message = message;
}
public override string ToString()
{
string tmp = Occurrence.ToString("yyyy-MM-ddTHH:mm:ss.FFFF") + " " + Level.ToString() + " " + Message + "\n";
return tmp;
}
}
public class LogContentX
{
public DateTime Occurrence { get; set; }
public LogLevel Level { get; set; }
public StackTrace Trace { get; set; }
public string Message { get; set; }
public LogContentX() { }
public LogContentX(LogLevel level, string message) { this.SetLog(level, message); }
public LogContentX(LogLevel level, string message, Exception e) { this.SetLog(level, message, e); }
public void SetLog(LogLevel level, string message)
{
this.Occurrence = DateTime.Now;
this.Level = level;
this.Trace = new StackTrace(true);//捕捉当前堆栈
this.Message = message;
}
public void SetLog(LogLevel level, string message, Exception e)
{
this.Occurrence = DateTime.Now;
this.Level = level;
this.Trace = new StackTrace(e, true);//捕捉当前异常堆栈堆栈
this.Message = message;
}
public override string ToString()
{
string tmp = Occurrence.ToString("yyyy-MM-ddTHH:mm:ss.FFFF") + " " + Level.ToString() + " " + Message + "\n";
return tmp;
}
public string TraceDetail()
{
string tmp = Occurrence.ToString("yyyy-MM-ddTHH:mm:ss.FFFF") + " " + Level.ToString() + " " + Message + "\n";
tmp += this.Trace.ToString() + "\r\n";
//StackFrame sf = Trace.GetFrame(0);
//tmp += $" Method: {sf.GetMethod()}\r\n";
//$" File: {sf.GetFileName()}\r\n" +
//$" Line Number: {sf.GetFileLineNumber()}\r\n";
return tmp;
}
public static string TraceDetail(LogContent log)
{
string tmp = log.Occurrence.ToString("yyyy-MM-ddTHH:mm:ss.FFFF") + " " + log.Level.ToString() + " " + log.Message + "\n";
tmp += log.Trace.ToString() + "\r\n";
//StackFrame sf = Trace.GetFrame(0);
//tmp += $" Method: {sf.GetMethod()}\r\n";
//$" File: {sf.GetFileName()}\r\n" +
//$" Line Number: {sf.GetFileLineNumber()}\r\n";
return tmp;
}
public string TraceTopFrame()
{
return this.Trace.GetFrame(0).ToString();
}
public StackFrame TraceTopStackFrame()
{
return Trace.GetFrame(0);
}
public StackFrame TraceBottomStackFrame()
{
return Trace.GetFrame(this.Trace.FrameCount - 1);
}
public int GetSize()
{
//在safe环境中无法使用sizeof(DateTime),sizeof(DateTime)用8字节代替
// Each character in a string is 2 bytes (UTF-16 encoding).
int total = sizeof(LogLevel) + this.Message.Length * 2 + 8;
for (int i = 0; i < this.Trace.FrameCount; i++)
{
StackFrame sf = this.Trace.GetFrame(i);
//sf.GetFileLineNumber();sf.GetFileName(); sf.GetMethod().Name;
total += sf.ToString().Length * 2;
}
return total;
}
public static int GetSize(LogContent log)
{
//在safe环境中无法使用sizeof(DateTime),sizeof(DateTime)用8字节代替
// Each character in a string is 2 bytes (UTF-16 encoding).
int total = sizeof(LogLevel) + log.Message.Length * 2 + 8;
for (int i = 0; i < log.Trace.FrameCount; i++)
{
StackFrame sf = log.Trace.GetFrame(i);
//sf.GetFileLineNumber();sf.GetFileName(); sf.GetMethod().Name;
total += sf.ToString().Length * 2;
}
return total;
}
}
public class LogBuffer
{
protected List<LogContent> buf = new List<LogContent>();
public List<LogContent> Buffer { get { return buf; } }
public LogBuffer()
{
buf = new List<LogContent>();
}
public LogBuffer(List<LogContent> buf)
{
this.buf = buf;
}
public void Insert(LogContent log)
{
this.buf.Add(log);
}
public void Insert(LogBuffer log)
{
foreach (var item in log.Buffer)
{
this.buf.Add(item);
}
}
public int LogSize()
{
int size = 0;
foreach (LogContent cnt in this.buf)
{
size += LogContentX.GetSize(cnt);
}
return size;
}
}
public class LogBufQuery
{
public List<LogContent> Buffer { get; set; }
public void TimeOrderAsc()
{
Buffer.Sort((x, y) => x.Occurrence.CompareTo(y.Occurrence));
}
public void TimeOrderDsc()
{
Buffer.Sort((x, y) => y.Occurrence.CompareTo(x.Occurrence));
}
public List<LogContent> FilterByLoglevel(LogLevel loglevel)
{
return Buffer.FindAll(log => log.Level == loglevel);
}
}
public class LogStatistic : LogBufQuery
{
private SqliteConnection connection;
private string dbfile = string.Empty;
//将db信息生成文本或文本文件
//寻找路径并创建文件
private void MakeFile()
{
string path = AppDomain.CurrentDomain.BaseDirectory;
// 获取当前应用程序域的名称(通常是程序集名称)
string assemblyName = AppDomain.CurrentDomain.FriendlyName;
// 去掉路径和扩展名,只保留文件名
assemblyName = Path.GetFileNameWithoutExtension(assemblyName);
// 组合成完整的路径
this.dbfile = System.IO.Path.Combine(path, assemblyName + ".db");
//确保数据库文件存在
string connectionString = $"Data Source={this.dbfile}";
try
{
this.connection = new SqliteConnection(connectionString);
connection.Open(); // 这将尝试打开数据库,如果不存在则会创建它
connection.Close();
}
catch (Exception ex)
{
throw ex;
}
}
//检查并创建数据表,确保必要的数据表存在。这里就固定了格式和标准。
private void EnsureDbTableExist()
{
//key-word形式
}
//连接db
//释放连接
//从Buffer中分析并向表中写入统计数据
//读表中数据
//插入或更新数据
//Clear
}
//将日志写成文本文件,注意在多线程环境下要排除线程互斥。
public class NtLog
{
private Queue<LogBuffer> Buff = new Queue<LogBuffer>();
public string LogPath { get; }
private string curfilepath = string.Empty;
private string errorLgFile = string.Empty; //定义从Exception到Fault这5个层级为Error
private Task task;
private Stopwatch watcher = new Stopwatch();
private long maxms, minms, lastms;
private volatile bool IsWriting = false;
public bool Writing { get { return IsWriting; } }
/// <summary>
/// 平均耗时
/// </summary>
public long AverageConsum
{
get
{
return (maxms + minms + lastms) / 3;
}
}
public NtLog()
{
this.LogPath = AppDomain.CurrentDomain.BaseDirectory;
创建日志文件夹
this.LogPath = CreateLogDirectory();
MakeLogFileName();
maxms = minms = lastms = 0;
}
public void OnLogging(List<LogContent> logs)
{
//#if DEBUG
// TempLog.logging($"查看原始数据。{logs.Count} ");//{logs.First().Message}
//#endif
this.Buff.Enqueue(new LogBuffer(logs));
//#if DEBUG
// TempLog.logging($"执行事件。{this.Buff.Count} {this.IsWriting}");
//#endif
//#if DEBUG
// TempLog.logging($"查看写缓存。{Temp.Buffer.Count} {Temp.Buffer.First().Message}");
//#endif
this.UpdatePathFileName();
if (this.IsWriting == false && this.Buff.Count > 0)
{
LogBuffer Temp = this.Buff.Dequeue();
while (this.Buff.Count > 0)
{
Temp.Insert(this.Buff.Dequeue());
}
WriteLogByThread(Temp);
}
}
public static string CreateLogDirectory()
{
string path = AppDomain.CurrentDomain.BaseDirectory;
// 获取当前应用程序域的名称(通常是程序集名称)
string assemblyName = AppDomain.CurrentDomain.FriendlyName;
// 去掉路径和扩展名,只保留文件名
assemblyName = Path.GetFileNameWithoutExtension(assemblyName);
// 组合成完整的路径
path = System.IO.Path.Combine(path, assemblyName + "Log");
//TempLog.logging(path);
//创建日志文件夹
Directory.CreateDirectory(path);
return path;
}
public void UpdatePathFileName()
{
string path = AppDomain.CurrentDomain.BaseDirectory;
// 获取当前应用程序域的名称(通常是程序集名称)
string assemblyName = AppDomain.CurrentDomain.FriendlyName;
// 去掉路径和扩展名,只保留文件名
assemblyName = Path.GetFileNameWithoutExtension(assemblyName);
// 组合成完整的路径
path = System.IO.Path.Combine(path, assemblyName + "Log");
//TempLog.logging(path);
//创建日志文件夹
Directory.CreateDirectory(path);
string dn = DateTime.Now.ToString("yyyy-MM-dd");
this.curfilepath = Path.Combine(this.LogPath, assemblyName + dn + ".log");
this.errorLgFile = Path.Combine(this.LogPath, assemblyName + dn + "err.log");
}
public void MakeLogFileName()
{
// 获取当前应用程序域的名称(通常是程序集名称)
string assemblyName = AppDomain.CurrentDomain.FriendlyName;
// 去掉路径和扩展名,只保留文件名
assemblyName = Path.GetFileNameWithoutExtension(assemblyName);
string dn = DateTime.Now.ToString("yyyy-MM-dd");
this.curfilepath = Path.Combine(this.LogPath, assemblyName + dn + ".log");
this.errorLgFile = Path.Combine(this.LogPath, assemblyName + dn + "err.log");
}
public void WriteLogFile()
{
using (StreamWriter writer = new StreamWriter(this.curfilepath, true)) // true表示追加模式
{
foreach (var Buffer in this.Buff)
{
foreach (var cnt in Buffer.Buffer)
{
writer.WriteLine(cnt.ToString());
}
}
}
}
public void WriteErrorLog()
{
using (StreamWriter writer = new StreamWriter(this.errorLgFile, true)) // true表示追加模式
{
foreach (var Buffer in this.Buff)
{
foreach (var cnt in Buffer.Buffer)
{
if (cnt.Level >= LogLevel.Exception)
writer.WriteLine(LogContentX.TraceDetail(cnt));
}
}
}
}
//发现它仍然阻塞主线程
//注意只有一个线程写,不能多个线程同时写文件。
//请注意,Buffer.Remove(cnt) 在循环中可能会导致问题,因为从集合中移除元素会改变集合的大小,从而可能导致迭代器失效。为了避免这个问题,可以先收集需要删除的元素,然后在循环结束后统一删除它们。
public void WriteLogByThread(LogBuffer logs)
{
this.watcher.Start();
this.IsWriting = true;
//#if DEBUG
// TempLog.logging($"BeofreWriteLog。{this.curfilepath} {this.errorLgFile}");
//#endif
// 使用Task.Run在后台线程中执行文件写入操作
this.task = Task.Run(() =>
{
//FileStream可以设置成独享锁定模式,防止 线程互斥
using (FileStream fs1 = new FileStream(this.curfilepath, FileMode.Append, FileAccess.Write, FileShare.None),
fs2 = new FileStream(this.errorLgFile, FileMode.Append, FileAccess.Write, FileShare.None))
{
using (StreamWriter writer = new StreamWriter(fs1), writer2 = new StreamWriter(fs2))
{
foreach (var cnt in logs.Buffer)
{
writer.WriteLine(cnt.ToString());
if (cnt.Level >= LogLevel.Warning)
writer2.WriteLine(LogContentX.TraceDetail(cnt));
}
}
}
//Buffer没有上锁是希望它尽快完成操作,但有风险
});
this.watcher.Stop();
this.IsWriting = false;
if (this.lastms > 0 && this.lastms > this.maxms)
{
this.maxms = this.lastms;
}
if (this.lastms > 0 && this.minms == 0)
this.minms = this.lastms;
if (this.lastms > 0 && this.lastms < this.minms)
{
this.minms = this.lastms;
}
this.lastms = watcher.ElapsedMilliseconds;
}
}
}
namespace Notify.App
{
enum SwitchApp
{
//"N" 78 0x4E
//"t"116 0x74
Nt = (0x4E << 8) | 0x74,
//ASCII 'A' 0x41 65
//ASCII 'B' 0x42 66
bRB = (0x41 << 8) | 0x42,//
ECHO = (0x08 << 8) | 0x0A //Turn; //ECHO 回显
}
}
namespace Notify.App.Cpolar
{
class DynamicCpolar
{
public static async Task<string> GetTunels(string token)
{
// 定义URL
string url = "http://localhost:9200/api/v1/tunnels";
// 定义Bearer令牌
//string token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjIxNzU0NjcsImlhdCI6MTcyMjAwMjY2NywiVXNlcklEIjowLCJVc2VybmFtZSI6IiIsIkVtYWlsIjoiaHV4eWNAcXEuY29tIiwiQXBpU2VydmljZVRva2VuIjoiZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SmxlSEFpT2pFM01qSXhOelUwTmpjc0ltbGhkQ0k2TVRjeU1qQXdNalkyTnl3aVZYTmxja2xFSWpveU56RXhNVEFzSWxWelpYSnVZVzFsSWpvaVVtbHpZU0lzSWtWdFlXbHNJam9pYUhWNGVXTkFjWEV1WTI5dEluMC5IMWVfYzl0VjZab1pabFlHVUxEMFlIWWN0VFl3RERMbm5MTFczNC1NZVhvIn0.oLtor_R5YnZgH3AQT17qCRXx5dRTDGUEP8amx8OD8Jo";
// 创建HttpClient实例
using (HttpClient client = new HttpClient())
{
// 设置请求头
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
// 发送GET请求
try
{
HttpResponseMessage response = await client.GetAsync(url);
// 确保HTTP成功状态值
response.EnsureSuccessStatusCode();
// 读取响应内容
string responseBody = await response.Content.ReadAsStringAsync();
// 打印响应内容
//Console.WriteLine(responseBody);
return responseBody;
}
catch (HttpRequestException hre)
{
//Console.WriteLine("\nException Caught!");
//Console.WriteLine($"Message :{hre.Message}");
throw hre;
//return "";
}
catch (Exception e)
{
throw e;
}
}
}
public static async Task<string> GetToken()
{
// 创建HttpClient实例
using (var client = new HttpClient())
{
// 设置请求URL
string url = "http://localhost:9200/api/v1/user/login";
// 准备要发送的JSON数据
var loginData = new
{
// 假设你需要发送用户名和密码
email = "youremail@qq.com",
password = "yourpassword"
};
// 将对象序列化为JSON字符串
string jsonContent = JsonConvert.SerializeObject(loginData); // 如果你使用System.Text.Json,则使用JsonSerializer.Serialize
// 创建StringContent实例,并设置媒体类型为application/json
StringContent content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
// 发送POST请求
try
{
HttpResponseMessage response = await client.PostAsync(url, content);
// 检查响应是否成功
response.EnsureSuccessStatusCode();
// 读取响应内容
string responseBody = await response.Content.ReadAsStringAsync();
// 输出响应内容
//Console.WriteLine(responseBody);
// 字符转Json并提取data属性值
// 使用 Newtonsoft.Json.Linq 来解析 JSON 字符串
JObject jsonObj = JObject.Parse(responseBody);
// 访问 data 属性并提取 token 值
if (jsonObj["data"] != null && jsonObj["data"].Type == JTokenType.Object)
{
JToken tokenToken = jsonObj["data"]["token"];
if (tokenToken != null && tokenToken.Type == JTokenType.String)
{
string token = tokenToken.Value<string>();
//Console.WriteLine($"Token: {token}");
return token;
}
else
{
//Console.WriteLine("Token is not a string or is null.");
throw new JsonException("Token is not a string or is null.");
//return "";
}
}
else
{
throw new JsonException("Data is null or not an object.");
//Console.WriteLine("Data is null or not an object.");
//return "";
}
}
catch (HttpRequestException he)
{
// 请求异常处理
//Console.WriteLine("\nException Caught!");
//Console.WriteLine("Message :{0} ", e.Message);
throw he;
}
catch (Exception e)
{
throw e;
}
//return "";
}
}
public static CpolarInfo GetCpolarInfoFromJsonString(string json)
{
//装载CpolarInfo数据
CpolarInfo cpolarInfo = new CpolarInfo();
try
{
// 解析JSON字符串为JObject
JObject jsonObject = JObject.Parse(json);
// 访问data对象下的items数组
JArray itemsArray = (JArray)jsonObject["data"]["items"];
//int total = (int)jsonObject["data"]["total"];
//获取total
cpolarInfo.total = (int)jsonObject["data"]["total"];
cpolarInfo.items = new item[cpolarInfo.total];
//Console.WriteLine($"{cpolarInfo.total}");
//初始化item,否则会报错
for (int j = 0; j < cpolarInfo.total; j++)
{
cpolarInfo.items[j] = new item
{
name = string.Empty,
create_datetime = string.Empty,
pubulic_url = string.Empty
};
}
int i = 0;
// 遍历items数组,提取publish_tunnels
foreach (JObject item in itemsArray)
{
// 提取name和public_url
string name = item["name"].ToString();
string public_url = item["public_url"].ToString();
string create_datetime = "";
// 访问publish_tunnels数组(假设每个条目至少有一个tunnel)
JArray tunnelsArray = (JArray)item["publish_tunnels"];
// 遍历publish_tunnels数组(这里假设我们只关心第一个tunnel的create_datetime)
foreach (JObject tunnel in tunnelsArray)
{
// 提取create_datetime
create_datetime = tunnel["create_datetime"].ToString();
// 打印或处理数据
//Console.WriteLine($"Name: {name}, Public URL: {public_url}, Create Datetime: {create_datetime}");
// 如果不需要处理多个tunnel,可以跳出内层循环
break; // 如果你想处理所有tunnel,请移除这行代码
}
// 使用Replace方法替换协议部分
string newUrl = public_url.Replace("tls://", "https://");
//Console.WriteLine($"{name},{create_datetime},{newUrl}");
// 打印或处理数据
//Console.WriteLine($"{name},{create_datetime},{public_url}");
//组装CpolarInfo
cpolarInfo.items[i].name = name;
cpolarInfo.items[i].create_datetime = create_datetime;
cpolarInfo.items[i].pubulic_url = newUrl;
i++;
}
}
catch (JsonException je)
{
throw je;
}
catch (Exception e)
{
throw e;
}
return cpolarInfo;
}
public static async Task<CpolarInfo> GetCpolarInfo()
{
string token = await GetToken();
// 输出响应内容
//Console.WriteLine(token);
string json = await GetTunels(token);
//装载CpolarInfo数据
CpolarInfo cpolarInfo = new CpolarInfo();
// 解析JSON字符串为JObject
JObject jsonObject = JObject.Parse(json);
// 访问data对象下的items数组
JArray itemsArray = (JArray)jsonObject["data"]["items"];
//int total = (int)jsonObject["data"]["total"];
//获取total
cpolarInfo.total = (int)jsonObject["data"]["total"];
cpolarInfo.items = new item[cpolarInfo.total];
//Console.WriteLine($"{cpolarInfo.total}");
//初始化item,否则会报错
for (int j = 0; j < cpolarInfo.total; j++)
{
cpolarInfo.items[j] = new item
{
name = string.Empty,
create_datetime = string.Empty,
pubulic_url = string.Empty
};
}
int i = 0;
// 遍历items数组,提取publish_tunnels
foreach (JObject item in itemsArray)
{
// 提取name和public_url
string name = item["name"].ToString();
string public_url = item["public_url"].ToString();
string create_datetime = "";
// 访问publish_tunnels数组(假设每个条目至少有一个tunnel)
JArray tunnelsArray = (JArray)item["publish_tunnels"];
// 遍历publish_tunnels数组(这里假设我们只关心第一个tunnel的create_datetime)
foreach (JObject tunnel in tunnelsArray)
{
// 提取create_datetime
create_datetime = tunnel["create_datetime"].ToString();
// 打印或处理数据
//Console.WriteLine($"Name: {name}, Public URL: {public_url}, Create Datetime: {create_datetime}");
// 如果不需要处理多个tunnel,可以跳出内层循环
break; // 如果你想处理所有tunnel,请移除这行代码
}
// 打印或处理数据
//Console.WriteLine($"Name: {name},Create Datetime:{create_datetime}, Public URL: {public_url}");
//Console.WriteLine($"{name},{create_datetime},{public_url}");
// 使用Replace方法替换协议部分
string newUrl = public_url.Replace("tls://", "https://");
//Console.WriteLine($"{name},{create_datetime},{newUrl}");
//Uri url = new Uri(public_url);
//public_url = url.Host;
//Console.WriteLine($"{name},{create_datetime},{public_url}");
//组装CpolarInfo
cpolarInfo.items[i].name = name;
cpolarInfo.items[i].create_datetime = create_datetime;
cpolarInfo.items[i].pubulic_url = newUrl;
i++;
}
return cpolarInfo;
}
public static DateTime GetLastUpdateFromCpolarInfp(CpolarInfo cptu)
{
DateTime now = DateTime.Now;
DateTime furthest = DateTime.Parse(cptu.items[cptu.total - 1].create_datetime);
DateTime tmp;
for (int i = 0; i < cptu.total - 1; i++)
{
tmp = DateTime.Parse(cptu.items[i].create_datetime);
if (furthest.CompareTo(tmp) > 0)
{
furthest = tmp;
}
}
return furthest;
}
}
public class CpolarCache
{
//public DateTime CacheOn { get; set; } //token请求时间
//public string tokenCache { get; set; }
public DateTime FurthestUpdate { get; set; } //CpolarInfo所有隧道的距离现在最长的时间
public CpolarInfo cpolarCache { get; set; }
}
public class CpolarInfo
{
public int total { get; set; }
public item[] items { get; set; }
}
public class item
{
public string name { get; set; }
public string create_datetime { get; set; }
public string pubulic_url { get; set; }
}
}
rBitsTest
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.IO;
using Newtonsoft;
using Newtonsoft.Json;
namespace rBitsTest
{
public class IPport
{
public string IP { get; set; }
public int Port { get; set; }
}
public class CpolarInfo
{
public int total { get; set; }
public item[] items { get; set; }
}
public class item
{
public string name { get; set; }
public string create_datetime { get; set; }
public string pubulic_url { get; set; }
}
internal class Program
{
static void Main(string[] args)
{
try
{
Console.WriteLine("Version:{0}", Assembly.GetEntryAssembly().GetName().Version.ToString());
string jsonFilePath = "ipport.json"; // 替换为你的JSON文件路径
// 读取文件内容
string jsonContent = File.ReadAllText(jsonFilePath);
// 反序列化JSON字符串到对象
List<IPport> ipaddrs = JsonConvert.DeserializeObject<List<IPport>>(jsonContent);
// 输出结果
foreach (var host in ipaddrs)
{
Console.WriteLine($"Host: IP: {host.IP}, Port: {host.Port}");
}
创建一个Random对象
//Random random = new Random((int)DateTime.Now.Ticks);
定义一个数组,其中包含更多你想要的值(例如1),以增加其出现的概率
//int[] weightedArray = new int[20];
//for (int i = 0; i < 10; i++) // 50% 是 1
//{
// weightedArray[i] = 1;
//}
//for (int i = 10; i < 16; i++) // 25% 是 1
//{
// weightedArray[i] = 0;
//}
//for (int i = 16; i < 20; i++) // 25% 是 1
//{
// weightedArray[i] = 2;
//}
从加权数组中随机选择一个元素
//int randomIndex = random.Next(weightedArray.Length);
//int randomNumber = weightedArray[randomIndex];
//var conhost = ipaddrs[randomNumber]; //randomNumber%2
//var conhost = new IPport();
var conhost = ipaddrs[2];
//conhost.Port = 25984;
//conhost.IP = "cn-hb-lt-tmp3.natfrp.cloud";
Console.WriteLine($"Selected Connect Host: IP: {conhost.IP}, Port: {conhost.Port}");
// 创建一个TcpClient实例并连接到服务器
TcpClient client = new TcpClient($"{conhost.IP}", conhost.Port);
// 获取一个NetworkStream对象以进行读写
NetworkStream stream = client.GetStream();
// 将消息转换为字节数组
//string message = "Hello from the client!";
//byte[] data = Encoding.ASCII.GetBytes(message);
//Flag1 Flag2 VerH VerL
byte[] data = { 0x4E, 0x74, 0x01, 0xF9, 0x00, 0x00, 0x00, 0x01 };
// 发送消息到服务器
stream.Write(data, 0, data.Length);
// 读取服务器的响应
byte[] buffer = new byte[4096];
int bytesRead = stream.Read(buffer, 0, buffer.Length);
// 将接收到的字节转换为字符串
string responseData = Encoding.ASCII.GetString(buffer, 0, bytesRead);
Console.WriteLine("Received from server: " + responseData);
Console.WriteLine("ReceivedBytes:{0}", bytesRead);
//将Json写入文件
File.WriteAllText("cpolarinfo.json", responseData);
// 关闭连接
client.Close();
}
catch (Exception e)
{
Console.WriteLine("Error: " + e.Message);
}
// 等待用户按键,以便在控制台中查看结果
//Console.WriteLine("Press Enter to continue...");
//Console.ReadLine();
// 设置定时器,6秒后执行ExitApplication方法
var timer = new System.Threading.Timer(ExitApplication, null, 6000, Timeout.Infinite);
Console.WriteLine("Press any key to exit...");
Console.ReadKey(); // 等待用户按键
// 如果用户提前按下了键,取消定时器
timer.Dispose();
}
static void ExitApplication(object state)
{
Console.WriteLine("Time's up! Exiting the application...");
Environment.Exit(0); // 退出程序
}
}
}