diff --git a/.gitignore b/.gitignore index 31f9861..6166492 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,5 @@ /Waste.Web.Entry/bin /Waste.Web.Entry/obj /.vs +/WasteConsoleTest/WasteConsoleTest/obj +/WasteConsoleTest/WasteConsoleTest/bin diff --git a/Waste.sln b/Waste.sln index 4fcd07c..cc775ed 100644 --- a/Waste.sln +++ b/Waste.sln @@ -25,6 +25,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Waste.Socket", "Waste.Socke EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Waste.MessageHandler", "Waste.MessageHandler\Waste.MessageHandler.csproj", "{49EB30D4-FEB7-42FB-87A1-BE0440413392}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WasteConsoleTest", "WasteConsoleTest\WasteConsoleTest\WasteConsoleTest.csproj", "{AB59B811-AADC-439B-9394-73CFF8F64C6F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -67,6 +69,10 @@ Global {49EB30D4-FEB7-42FB-87A1-BE0440413392}.Debug|Any CPU.Build.0 = Debug|Any CPU {49EB30D4-FEB7-42FB-87A1-BE0440413392}.Release|Any CPU.ActiveCfg = Release|Any CPU {49EB30D4-FEB7-42FB-87A1-BE0440413392}.Release|Any CPU.Build.0 = Release|Any CPU + {AB59B811-AADC-439B-9394-73CFF8F64C6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AB59B811-AADC-439B-9394-73CFF8F64C6F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AB59B811-AADC-439B-9394-73CFF8F64C6F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AB59B811-AADC-439B-9394-73CFF8F64C6F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -81,6 +87,7 @@ Global {AE2A0447-5722-4D5B-89A5-6355E29FB706} = {A10953C4-FF58-42A1-AAEF-7B68018F5EDB} {82C5EF90-C84C-4A83-A732-B82E0E429BDF} = {A10953C4-FF58-42A1-AAEF-7B68018F5EDB} {49EB30D4-FEB7-42FB-87A1-BE0440413392} = {A10953C4-FF58-42A1-AAEF-7B68018F5EDB} + {AB59B811-AADC-439B-9394-73CFF8F64C6F} = {A10953C4-FF58-42A1-AAEF-7B68018F5EDB} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {086B267B-9152-4816-8D48-30032ACB8A2C} diff --git a/WasteConsoleTest/.vs/WasteConsoleTest/DesignTimeBuild/.dtbcache.v2 b/WasteConsoleTest/.vs/WasteConsoleTest/DesignTimeBuild/.dtbcache.v2 new file mode 100644 index 0000000..a2bfc5a Binary files /dev/null and b/WasteConsoleTest/.vs/WasteConsoleTest/DesignTimeBuild/.dtbcache.v2 differ diff --git a/WasteConsoleTest/.vs/WasteConsoleTest/v16/.suo b/WasteConsoleTest/.vs/WasteConsoleTest/v16/.suo new file mode 100644 index 0000000..7b3b74c Binary files /dev/null and b/WasteConsoleTest/.vs/WasteConsoleTest/v16/.suo differ diff --git a/WasteConsoleTest/.vs/slnx.sqlite b/WasteConsoleTest/.vs/slnx.sqlite new file mode 100644 index 0000000..c0861d3 Binary files /dev/null and b/WasteConsoleTest/.vs/slnx.sqlite differ diff --git a/WasteConsoleTest/.vs/slnx.sqlite-journal b/WasteConsoleTest/.vs/slnx.sqlite-journal new file mode 100644 index 0000000..22e3f2c Binary files /dev/null and b/WasteConsoleTest/.vs/slnx.sqlite-journal differ diff --git a/WasteConsoleTest/WasteConsoleTest.sln b/WasteConsoleTest/WasteConsoleTest.sln new file mode 100644 index 0000000..9e9734c --- /dev/null +++ b/WasteConsoleTest/WasteConsoleTest.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31402.337 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WasteConsoleTest", "WasteConsoleTest\WasteConsoleTest.csproj", "{E365B702-88E9-4961-A29E-641BB7E1CE5A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E365B702-88E9-4961-A29E-641BB7E1CE5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E365B702-88E9-4961-A29E-641BB7E1CE5A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E365B702-88E9-4961-A29E-641BB7E1CE5A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E365B702-88E9-4961-A29E-641BB7E1CE5A}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {904AE273-F940-4429-A69A-26F4D2705412} + EndGlobalSection +EndGlobal diff --git a/WasteConsoleTest/WasteConsoleTest/Program.cs b/WasteConsoleTest/WasteConsoleTest/Program.cs new file mode 100644 index 0000000..08eff49 --- /dev/null +++ b/WasteConsoleTest/WasteConsoleTest/Program.cs @@ -0,0 +1,395 @@ +using MessagePack; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Net.WebSockets; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; + +namespace WasteConsoleTest +{ + class Program + { + private static WSocketClientHelp wSocketClient = null; + public static string Secret = "g8OEiOAaKjYK38aj"; + public static string SecretHash = "9729e43752011ad4"; + static async Task Main(string[] args) + { + var builder = new HostBuilder().ConfigureServices((hostContext, services) => + { + services.AddHttpClient(); + services.AddTransient(); + }).UseConsoleLifetime(); + var host = builder.Build(); + wSocketClient = new WSocketClientHelp("wss://api.device.suzhou.ljflytjl.cn/device_rpc"); + wSocketClient.OnOpen -= WSocketClient_OnOpen; + wSocketClient.OnMessage -= WSocketClient_OnMessage; + wSocketClient.OnClose -= WSocketClient_OnClose; + wSocketClient.OnError -= WSocketClient_OnError; + + wSocketClient.OnOpen += WSocketClient_OnOpen; + wSocketClient.OnMessage += WSocketClient_OnMessage; + wSocketClient.OnClose += WSocketClient_OnClose; + wSocketClient.OnError += WSocketClient_OnError; + wSocketClient.Open(); + var myService = host.Services.GetRequiredService(); + SetTimeOut(); + while (true) + { + string cmd = Console.ReadLine(); + //退出 + if (cmd == "exit") + { + Console.WriteLine("退出请求"); + wSocketClient.Close(); + break; + } + else + //测试sayhello + if (cmd.ToLower() == "sayhello") + { + var senddata = @"{ + ""type"": 1, + ""invocationId"": ""Nil"", + ""target"": ""sayHello"", + ""arguments"": [ + ""Hello Test Message"" + ] +}"; + wSocketClient.Send(senddata); + } + //获取token + else if (cmd.ToLower() == "gettoken") + { + var senddata = @"{ + ""type"": 1, + ""invocationId"": ""Nil"", + ""target"": ""getToken"", + ""arguments"": [ + ""sz_data"" + ] +}"; + wSocketClient.Send(senddata); + } + //测试token的有效期 + else if (cmd.ToLower() == "testtoken") + { + await myService.TestTokenAsync(); + } + //测试上报 + else if (cmd.ToLower() == "postdata") + { + await myService.Garbages(); + } + } + } + private static void WSocketClient_OnError(object sender, Exception ex) + { + Console.WriteLine($"发生异常:{ex.Message}"); + } + + private static void WSocketClient_OnClose(object sender, EventArgs e) + { + Console.WriteLine($"已关闭"); + } + + private static void WSocketClient_OnMessage(object sender, string data) + { + //处理的消息错误将会忽略 + try + { + //查看数据是否有token + var jsondata = JsonConvert.DeserializeObject(data); + if (jsondata != null && jsondata.type == 1 && !string.IsNullOrEmpty(jsondata.target) && jsondata.target.ToLower() == "token" && jsondata.arguments != null && jsondata.arguments.Count == 1) + { + var token = jsondata.arguments.First(); + //保存token到文件中 + var path = AppDomain.CurrentDomain.BaseDirectory + "File"; + var filePath = path + @"\token.txt"; + if (!Directory.Exists(path)) + { + Directory.CreateDirectory(path); + } + if (File.Exists(filePath)) + { + File.Delete(filePath); + } + using (var fileStream = new FileStream(filePath, FileMode.CreateNew)) + { + byte[] content = Encoding.UTF8.GetBytes(token); + fileStream.Write(content, 0, content.Length); + } + } + Console.WriteLine($"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")},收到的消息:{data}"); + } + catch (Exception ex) + { + + } + + } + + public interface IMyService + { + /// + /// 测试token有效期 + /// + Task TestTokenAsync(); + /// + /// 传送垃圾数据 + /// + /// + Task Garbages(); + } + + public class MyService : IMyService + { + private readonly IHttpClientFactory _clientFactory; + + public MyService(IHttpClientFactory clientFactory) + { + _clientFactory = clientFactory; + } + /// + /// 传送垃圾数据 + /// + /// + public async Task Garbages() + { + try + { + string token = gettoken(); + if (!string.IsNullOrEmpty(token)) + { + int timestamp = GetTimestamp(); + var garbageC2SDto = new GarbageC2SDto + { + weight = 10.01, + trash = "251658245", + scanningTime = timestamp, + d_status = 0, + type = 1 + }; + int nonce = GetNonce(); + string[] paramlist = new string[] { + garbageC2SDto.weight.ToString(),garbageC2SDto.trash,garbageC2SDto.type.ToString(),garbageC2SDto.scanningTime.ToString(),garbageC2SDto.d_status.ToString() + }; + string sign = GetUserApiSign(Secret, paramlist); + var request = new HttpRequestMessage(HttpMethod.Post, +"https://api.data.suzhou.ljflytjl.cn/api/Garbages"); + request.Headers.Add("Authorization", $"Bearer {token}"); + request.Headers.Add("secret", Secret); + request.Headers.Add("nonce", nonce.ToString()); + request.Headers.Add("time", timestamp.ToString()); + request.Headers.Add("sign", sign); + var message = JsonConvert.SerializeObject(garbageC2SDto); + request.Content = new StringContent(message, Encoding.UTF8, "application/json"); + var client = _clientFactory.CreateClient(); + var response = await client.SendAsync(request); + var result = await response.Content.ReadAsStringAsync(); + if (response.IsSuccessStatusCode) + { + Console.WriteLine($"上报成功:{result}"); + } + else + { + Console.WriteLine($"上报失败:{response.StatusCode},{result}"); + } + } + else + { + Console.Write("token未找到"); + } + } + catch (Exception ex) + { + + + } + } + + /// + /// 测试token有效期 + /// + public async Task TestTokenAsync() + { + var request = new HttpRequestMessage(HttpMethod.Get, + "https://api.data.suzhou.ljflytjl.cn/api/hello/device"); + string token = gettoken(); + if (!string.IsNullOrEmpty(token)) + { + request.Headers.Add("Authorization", $"Bearer {token}"); + var client = _clientFactory.CreateClient(); + var response = await client.SendAsync(request); + var result = await response.Content.ReadAsStringAsync(); + if (response.IsSuccessStatusCode) + { + Console.WriteLine($"token可用:{result}"); + } + else + { + Console.WriteLine($"token已过期:{response.StatusCode},{result}"); + } + } + else + { + Console.Write("token未找到"); + } + } + /// + /// 获取时间戳 + /// + /// + private int GetTimestamp() + { + DateTime utcTime = TimeZoneInfo.ConvertTimeToUtc(DateTime.Now); + DateTime utcStartTime = new DateTime(1970, 1, 1, 0, 0, 0, 0); + int timestamp = Convert.ToInt32((utcTime-utcStartTime).TotalSeconds); + return timestamp; + } + /// + /// 获取随机数 + /// + /// + public int GetNonce() + { + var random = new Random(); + int nonce = random.Next(1, Int32.MaxValue); + return nonce; + } + /// + /// 获取签名 + /// + /// + /// + /// + public string GetUserApiSign(string secret, params string[] dataparams) + { + StringBuilder sb = new StringBuilder(); + string ApiSecret = "EtifGTppTL0TTjie"; + if (dataparams != null && dataparams.Length > 0) + { + foreach (var item in dataparams) + { + sb.Append(item); + } + } + if (!string.IsNullOrEmpty(secret)) + { + sb.Append(secret); + } + else + { + sb.Append(ApiSecret); + } + string str = sb.ToString(); + MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider(); + string sign = System.BitConverter.ToString(md5.ComputeHash(System.Text.UTF8Encoding.Default.GetBytes(str)), 4, 8).Replace("-", ""); + sign = sign.ToLower(); + return sign; + } + /// + /// 获取token + /// + /// + private string gettoken() + { + var filePath = AppDomain.CurrentDomain.BaseDirectory + @"File\token.txt"; + string token = string.Empty; + if (File.Exists(filePath)) + { + token = File.ReadAllText(filePath); + } + return token; + } + } + /// + /// 向服务端推送测试用垃圾采集数据 + /// + public class GarbageC2SDto //客户端向服务端请求的DTO + { + /// + /// 垃圾称重数据,64位浮点进度,单位为千克 + /// + public double weight { get; set; } + /// + /// 垃圾桶编码 + /// + public string trash { get; set; } + /// + /// 垃圾类型,缺省类型 : 0,厨余垃圾 : 1,可回收物 : 2,有害垃圾 : 3,其他垃圾 : 4 + /// + + public int type { get; set; } + /// + /// 数据扫描时间,UNIX时间戳 + /// + public int scanningTime { get; set; } + /// + /// 设备状态,使用中 : 0:使用中,异常 : 1,检修 : 2,检修结束 : 3,启用 : 4,未知 : 5 + /// + public int d_status { get; set; } + } + /// + /// 响应的数据 + /// + public class ResponseData + { + /// + /// 类型,6-心跳包,1-token,3-其他 + /// + public int type { get; set; } + /// + /// 请求id + /// + public string invocationId { get; set; } + /// + /// 结果 + /// + public string result { get; set; } + /// + /// 目标 + /// + public string target { get; set; } + /// + /// 参数 + /// + public List arguments { get; set; } + } + + private static void WSocketClient_OnOpen(object sender, EventArgs e) + { + Console.WriteLine($"已连接"); + } + public static void SetTimeOut() + { + Task.Run(() => + { + DateTime startime = DateTime.Now; + while (wSocketClient.State == WebSocketState.Open) + { + if ((DateTime.Now - startime).TotalSeconds >= 13) + { + //发送心跳包 + var message = @"{ + ""type"": 6 + }"; + wSocketClient.Send(message); + } + } + }); + } + private static byte[] RemoveSeparator(byte[] data) + { + List t = new List(data); + t.Remove(0x1e); + return t.ToArray(); + } + } +} diff --git a/WasteConsoleTest/WasteConsoleTest/WSocketClientHelp.cs b/WasteConsoleTest/WasteConsoleTest/WSocketClientHelp.cs new file mode 100644 index 0000000..5262937 --- /dev/null +++ b/WasteConsoleTest/WasteConsoleTest/WSocketClientHelp.cs @@ -0,0 +1,239 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.WebSockets; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace WasteConsoleTest +{ + public class WSocketClientHelp + { + ClientWebSocket ws = null; + Uri uri = null; + bool isUserClose = false;//是否最后由用户手动关闭 + public static string Secret = "g8OEiOAaKjYK38aj"; + public static string SecretHash = "9729e43752011ad4"; + public static string deviceid = "08d95bb6-a0f1-4964-85ac-9786b3571656"; + + // + /// WebSocket状态 + /// + public WebSocketState? State { get => ws?.State; } + + /// + /// 包含一个数据的事件 + /// + public delegate void MessageEventHandler(object sender, string data); + public delegate void ErrorEventHandler(object sender, Exception ex); + + /// + /// 连接建立时触发 + /// + public event EventHandler OnOpen; + /// + /// 客户端接收服务端数据时触发 + /// + public event MessageEventHandler OnMessage; + /// + /// 通信发生错误时触发 + /// + public event ErrorEventHandler OnError; + /// + /// 连接关闭时触发 + /// + public event EventHandler OnClose; + + public WSocketClientHelp(string wsUrl) + { + uri = new Uri(wsUrl); + ws = new ClientWebSocket(); + } + + /// + /// 打开链接 + /// + public void Open() + { + Task.Run(async () => + { + if (ws.State == WebSocketState.Connecting || ws.State == WebSocketState.Open) + return; + + string netErr = string.Empty; + try + { + //初始化链接 + isUserClose = false; + ws = new ClientWebSocket(); + // ws.Options.AddSubProtocol("protocol1"); //使用的协议 + ws.Options.SetRequestHeader("device", deviceid); //设备ID + ws.Options.SetRequestHeader("secret", SecretHash); //设备secrethash + ws.Options.SetRequestHeader("time", GetTimestamp().ToString()); //时间戳 + ws.Options.SetRequestHeader("os", "12"); //操作系统,Android ArmV7 + ws.Options.SetRequestHeader("script", "2"); //设备支持的脚本语言运行环境,1-lua5.4 2-javascript + ws.Options.SetRequestHeader("baseProgrameLang", "10"); //宿主程序语言,java + ws.Options.SetRequestHeader("dev", "true");//开发环境,bool类型 + await ws.ConnectAsync(uri, CancellationToken.None); //建立连接 + + if (OnOpen != null) + OnOpen(ws, new EventArgs()); + + Send(@"{""protocol"":""json"", ""version"":1}");//建立之后第一步进行握手,使用json类型 + + //全部消息容器 + List bs = new List(); + //缓冲区 + var buffer = new byte[1024 * 4]; + //监听Socket信息 + WebSocketReceiveResult result = await ws.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None); + //是否关闭 + while (!result.CloseStatus.HasValue) + { + //文本消息 + if (result.MessageType == WebSocketMessageType.Text) + { + bs.AddRange(buffer.Take(result.Count)); + + //消息是否已接收完全 + if (result.EndOfMessage) + { + var arr = RemoveSeparator(bs.ToArray());//过滤掉记录分隔符 + + //发送过来的消息 + string userMsg = Encoding.UTF8.GetString(arr, 0, arr.Length); + + if (OnMessage != null) + OnMessage(ws, userMsg); + + //清空消息容器 + bs = new List(); + } + } + //继续监听Socket信息 + result = await ws.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None); + } + ////关闭WebSocket(服务端发起) + //await ws.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None); + } + catch (Exception ex) + { + netErr = "发生错误" + ex.Message; + + if (OnError != null) + OnError(ws, ex); + + //if (ws != null && ws.State == WebSocketState.Open) + // //关闭WebSocket(客户端发起) + // await ws.CloseAsync(WebSocketCloseStatus.Empty, ex.Message, CancellationToken.None); + } + finally + { + if (!isUserClose) + Close(ws.CloseStatus.Value, ws.CloseStatusDescription + netErr); + } + }); + + } + /// + /// 增加记录分隔符 + /// + /// + /// + private static byte[] AddSeparator(byte[] data) + { + List t = new List(data) { 0x1e };//0x1e record separator + return t.ToArray(); + } + //删除记录分隔符 + private static byte[] RemoveSeparator(byte[] data) + { + List t = new List(data); + t.Remove(0x1e); + return t.ToArray(); + } + /// + /// 获取时间戳 + /// + /// + private int GetTimestamp() + { + DateTime dateTimeStart = TimeZoneInfo.ConvertTimeToUtc(new DateTime(1970, 1, 1, 8, 0, 0)); + int timestamp = Convert.ToInt32((DateTime.Now - dateTimeStart).TotalSeconds); + return timestamp; + } + /// + /// 使用连接发送文本消息 + /// + /// + /// + /// 是否尝试了发送 + public bool Send(string mess) + { + if (ws.State != WebSocketState.Open) + return false; + + Task.Run(async () => + { + Console.WriteLine($"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")},发送数据:{mess}"); + var replyMess = Encoding.UTF8.GetBytes(mess); + //发送消息,结尾必须携带记录分隔符 + await ws.SendAsync(new ArraySegment(AddSeparator(replyMess)), WebSocketMessageType.Text, true, CancellationToken.None); + }); + + return true; + } + + /// + /// 使用连接发送字节消息 + /// + /// + /// + /// 是否尝试了发送 + public bool Send(byte[] bytes) + { + if (ws.State != WebSocketState.Open) + return false; + + Task.Run(async () => + { + //发送消息 + await ws.SendAsync(new ArraySegment(bytes), WebSocketMessageType.Binary, true, CancellationToken.None); + }); + + return true; + } + + /// + /// 关闭连接 + /// + public void Close() + { + isUserClose = true; + Close(WebSocketCloseStatus.NormalClosure, "用户手动关闭"); + } + + public void Close(WebSocketCloseStatus closeStatus, string statusDescription) + { + Task.Run(async () => + { + try + { + //关闭WebSocket(客户端发起) + await ws.CloseAsync(closeStatus, statusDescription, CancellationToken.None); + } + catch (Exception ex) + { + + } + + ws.Abort(); + ws.Dispose(); + + if (OnClose != null) + OnClose(ws, new EventArgs()); + }); + } + } +} diff --git a/WasteConsoleTest/WasteConsoleTest/WasteConsoleTest.csproj b/WasteConsoleTest/WasteConsoleTest/WasteConsoleTest.csproj new file mode 100644 index 0000000..10d3985 --- /dev/null +++ b/WasteConsoleTest/WasteConsoleTest/WasteConsoleTest.csproj @@ -0,0 +1,16 @@ + + + + Exe + net5.0 + + + + + + + + + + +