websocket测试控制台

This commit is contained in:
Hinse 2021-08-11 08:19:44 +08:00
parent 6a221c14ba
commit a70384370a
10 changed files with 684 additions and 0 deletions

2
.gitignore vendored
View File

@ -25,3 +25,5 @@
/Waste.Web.Entry/bin
/Waste.Web.Entry/obj
/.vs
/WasteConsoleTest/WasteConsoleTest/obj
/WasteConsoleTest/WasteConsoleTest/bin

View File

@ -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}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -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

View File

@ -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<IMyService, MyService>();
}).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<IMyService>();
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<ResponseData>(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
{
/// <summary>
/// 测试token有效期
/// </summary>
Task TestTokenAsync();
/// <summary>
/// 传送垃圾数据
/// </summary>
/// <returns></returns>
Task Garbages();
}
public class MyService : IMyService
{
private readonly IHttpClientFactory _clientFactory;
public MyService(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
/// <summary>
/// 传送垃圾数据
/// </summary>
/// <returns></returns>
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)
{
}
}
/// <summary>
/// 测试token有效期
/// </summary>
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未找到");
}
}
/// <summary>
/// 获取时间戳
/// </summary>
/// <returns></returns>
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;
}
/// <summary>
/// 获取随机数
/// </summary>
/// <returns></returns>
public int GetNonce()
{
var random = new Random();
int nonce = random.Next(1, Int32.MaxValue);
return nonce;
}
/// <summary>
/// 获取签名
/// </summary>
/// <param name="secret"></param>
/// <param name="dataparams"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 获取token
/// </summary>
/// <returns></returns>
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;
}
}
/// <summary>
/// 向服务端推送测试用垃圾采集数据
/// </summary>
public class GarbageC2SDto //客户端向服务端请求的DTO
{
/// <summary>
/// 垃圾称重数据,64位浮点进度单位为千克
/// </summary>
public double weight { get; set; }
/// <summary>
/// 垃圾桶编码
/// </summary>
public string trash { get; set; }
/// <summary>
/// 垃圾类型,缺省类型 : 0,厨余垃圾 : 1,可回收物 : 2,有害垃圾 : 3,其他垃圾 : 4
/// </summary>
public int type { get; set; }
/// <summary>
/// 数据扫描时间,UNIX时间戳
/// </summary>
public int scanningTime { get; set; }
/// <summary>
/// 设备状态,使用中 : 0:使用中,异常 : 1,检修 : 2,检修结束 : 3,启用 : 4,未知 : 5
/// </summary>
public int d_status { get; set; }
}
/// <summary>
/// 响应的数据
/// </summary>
public class ResponseData
{
/// <summary>
/// 类型,6-心跳包,1-token,3-其他
/// </summary>
public int type { get; set; }
/// <summary>
/// 请求id
/// </summary>
public string invocationId { get; set; }
/// <summary>
/// 结果
/// </summary>
public string result { get; set; }
/// <summary>
/// 目标
/// </summary>
public string target { get; set; }
/// <summary>
/// 参数
/// </summary>
public List<string> 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<byte> t = new List<byte>(data);
t.Remove(0x1e);
return t.ToArray();
}
}
}

View File

@ -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";
// <summary>
/// WebSocket状态
/// </summary>
public WebSocketState? State { get => ws?.State; }
/// <summary>
/// 包含一个数据的事件
/// </summary>
public delegate void MessageEventHandler(object sender, string data);
public delegate void ErrorEventHandler(object sender, Exception ex);
/// <summary>
/// 连接建立时触发
/// </summary>
public event EventHandler OnOpen;
/// <summary>
/// 客户端接收服务端数据时触发
/// </summary>
public event MessageEventHandler OnMessage;
/// <summary>
/// 通信发生错误时触发
/// </summary>
public event ErrorEventHandler OnError;
/// <summary>
/// 连接关闭时触发
/// </summary>
public event EventHandler OnClose;
public WSocketClientHelp(string wsUrl)
{
uri = new Uri(wsUrl);
ws = new ClientWebSocket();
}
/// <summary>
/// 打开链接
/// </summary>
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<byte> bs = new List<byte>();
//缓冲区
var buffer = new byte[1024 * 4];
//监听Socket信息
WebSocketReceiveResult result = await ws.ReceiveAsync(new ArraySegment<byte>(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<byte>();
}
}
//继续监听Socket信息
result = await ws.ReceiveAsync(new ArraySegment<byte>(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);
}
});
}
/// <summary>
/// 增加记录分隔符
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
private static byte[] AddSeparator(byte[] data)
{
List<byte> t = new List<byte>(data) { 0x1e };//0x1e record separator
return t.ToArray();
}
//删除记录分隔符
private static byte[] RemoveSeparator(byte[] data)
{
List<byte> t = new List<byte>(data);
t.Remove(0x1e);
return t.ToArray();
}
/// <summary>
/// 获取时间戳
/// </summary>
/// <returns></returns>
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;
}
/// <summary>
/// 使用连接发送文本消息
/// </summary>
/// <param name="ws"></param>
/// <param name="mess"></param>
/// <returns>是否尝试了发送</returns>
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<byte>(AddSeparator(replyMess)), WebSocketMessageType.Text, true, CancellationToken.None);
});
return true;
}
/// <summary>
/// 使用连接发送字节消息
/// </summary>
/// <param name="ws"></param>
/// <param name="mess"></param>
/// <returns>是否尝试了发送</returns>
public bool Send(byte[] bytes)
{
if (ws.State != WebSocketState.Open)
return false;
Task.Run(async () =>
{
//发送消息
await ws.SendAsync(new ArraySegment<byte>(bytes), WebSocketMessageType.Binary, true, CancellationToken.None);
});
return true;
}
/// <summary>
/// 关闭连接
/// </summary>
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());
});
}
}
}

View File

@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MessagePack" Version="2.2.85" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="System.Net.WebSockets.Client" Version="4.3.2" />
</ItemGroup>
</Project>