Browse Source

tcp连接逻辑

添加登录动画
master
sc 6 days ago
parent
commit
9abaeaf43b
  1. 4
      AppShell.xaml.cs
  2. 158
      Class/SecureJsonService.cs
  3. 20
      Class/TcpServer.cs
  4. 3
      Models/AppModels.cs
  5. 17
      View/LogPage.xaml
  6. 14
      View/LogPage.xaml.cs

4
AppShell.xaml.cs

@ -22,7 +22,9 @@ namespace SunlightAggregationTerminal
await Navigation.PushModalAsync(new NavigationPage(logpage));
}
else
{//发送登录请求
{
//发送登录请求
if (await AppModels.LogIn())
{//拒绝登陆时打开登录页面
var logpage = new View.LogPage();

158
Class/SecureJsonService.cs

@ -0,0 +1,158 @@
using System;
using System.Collections.Generic;
using System.IO.Compression;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
namespace SunlightAggregationTerminal.Class
{
public class SecureJsonService
{
private readonly byte[] _aesKey = Encoding.UTF8.GetBytes("12345678901234567890123456789012");
/// <summary>
/// 调用一:发送端处理
/// 流程:JSON序列化 -> GZip压缩 -> AES加密 -> Base64编码
/// </summary>
public string CompressEncryptAndSend(object dataObject)
{
try
{
// 1. JSON 序列化 (使用 System.Text.Json 进行最小化处理)
// JsonSerializerOptions 默认不包含缩进,即最小化
string jsonString = JsonSerializer.Serialize(dataObject);
byte[] jsonBytes = Encoding.UTF8.GetBytes(jsonString);
// 2. GZip 压缩
byte[] compressedBytes = CompressBytes(jsonBytes);
// 3. AES 加密
byte[] encryptedBytes = EncryptBytes(compressedBytes);
// 4. Base64 编码 (转为字符串以便在网络传输)
string finalPayload = Convert.ToBase64String(encryptedBytes);
return finalPayload;
}
catch (Exception ex)
{
Console.WriteLine($"发送端处理错误: {ex.Message}");
throw;
}
}
/// <summary>
/// 调用二:接收端处理
/// 流程:Base64解码 -> AES解密 -> GZip解压 -> JSON反序列化
/// </summary>
public T? ReceiveDecryptAndDecompress<T>(string payload)
{
try
{
// 1. Base64 解码
byte[] encryptedBytes = Convert.FromBase64String(payload);
// 2. AES 解密
byte[] compressedBytes = DecryptBytes(encryptedBytes);
// 3. GZip 解压
byte[] jsonBytes = DecompressBytes(compressedBytes);
// 4. JSON 反序列化
string jsonString = Encoding.UTF8.GetString(jsonBytes);
T result = JsonSerializer.Deserialize<T>(jsonString);
return result;
}
catch (Exception)
{
throw;
}
}
// --- 底层辅助方法 ---
private byte[] CompressBytes(byte[] data)
{
using (var outputStream = new MemoryStream())
{
using (var gzipStream = new GZipStream(outputStream, CompressionLevel.Optimal))
{
gzipStream.Write(data, 0, data.Length);
}
return outputStream.ToArray();
}
}
private byte[] DecompressBytes(byte[] data)
{
using (var inputStream = new MemoryStream(data))
{
using (var gzipStream = new GZipStream(inputStream, CompressionMode.Decompress))
{
using (var outputStream = new MemoryStream())
{
gzipStream.CopyTo(outputStream);
return outputStream.ToArray();
}
}
}
}
private byte[] EncryptBytes(byte[] data)
{
using (Aes aes = Aes.Create())
{
aes.Key = _aesKey;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
aes.GenerateIV(); // 每次加密生成随机IV
var encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
using (var ms = new MemoryStream())
{
// 重要:先将 IV 写入流中,以便解密时读取
ms.Write(aes.IV, 0, aes.IV.Length);
using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
cs.Write(data, 0, data.Length);
cs.FlushFinalBlock();
return ms.ToArray();
}
}
}
}
private byte[] DecryptBytes(byte[] data)
{
using (Aes aes = Aes.Create())
{
aes.Key = _aesKey;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
// 从数据开头读取 IV (AES IV 固定为 16 字节)
byte[] iv = new byte[16];
Buffer.BlockCopy(data, 0, iv, 0, iv.Length);
aes.IV = iv;
var decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
using (var ms = new MemoryStream(data, iv.Length, data.Length - iv.Length))
{
using (var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
{
using (var resultStream = new MemoryStream())
{
cs.CopyTo(resultStream);
return resultStream.ToArray();
}
}
}
}
}
}
}

20
Class/TcpServer.cs

@ -21,6 +21,10 @@ namespace SunlightAggregationTerminal.Class
ServerName = Name;
ServerPassword = Password;
ServerTerminal = Terminal;
_= TcpClient(tcpClient, ServerIP, "7789");
}
public static async void Query(string Dat)
{
@ -30,10 +34,8 @@ namespace SunlightAggregationTerminal.Class
}
private static async Task CreateCustomService()
public static async Task TcpClient(TcpClient tcpClient, string ip, string port)
{
tcpClient.Config.SetRemoteIPHost(ServerIP);
tcpClient.Connecting = (client, e) => { return EasyTask.CompletedTask; };//即将连接到服务器,此时已经创建socket,但是还未建立tcp
tcpClient.Connected = (client, e) => { return EasyTask.CompletedTask; };//成功连接到服务器
tcpClient.Closing = (client, e) => { return EasyTask.CompletedTask; };//即将从服务器断开连接。此处仅主动断开才有效。
@ -44,10 +46,22 @@ namespace SunlightAggregationTerminal.Class
//从服务器收到信息。但是一般byteBlock和requestInfo会根据适配器呈现不同的值。
var mes = e.Memory.Span.ToString(Encoding.UTF8);
tcpClient.Logger.Info($"客户端接收到信息:{mes}");
return EasyTask.CompletedTask;
};
#endregion
await tcpClient.SetupAsync(new TouchSocketConfig()
.SetRemoteIPHost(ip + ":" + port)
.ConfigurePlugins(a =>
{
})
.ConfigureContainer(a =>
{
}
));
await tcpClient.ConnectAsync();//调用连接,当连接不成功时,会抛出异常。
}
}

3
Models/AppModels.cs

@ -39,6 +39,9 @@ namespace SunlightAggregationTerminal.Models
App.GlobalData.MessageNotificationMode = Convert.ToBoolean(dat.Field<object>("MessageNotificationMode"));
TcpServer.Configuration(App.GlobalData.ServerID, App.GlobalData.User, App.GlobalData.UserPassword, dat.Field<string>("GUID") ?? "Not");
//启动tcp
// TcpServer.CreateCustomService();
}
}
}

17
View/LogPage.xaml

@ -3,6 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="SunlightAggregationTerminal.View.LogPage"
Title="登录">
<Grid>
<VerticalStackLayout Padding="30" Spacing="10"
VerticalOptions="Center"
HorizontalOptions="Center"
@ -75,4 +76,20 @@
Margin="0,10,0,0"
Clicked="Log_Clicked"/>
</VerticalStackLayout>
<Grid x:Name="LoadingIndicator" BackgroundColor="Gray"
IsVisible="False">
<VerticalStackLayout Padding="30" Spacing="10"
VerticalOptions="Center"
HorizontalOptions="Center">
<ActivityIndicator IsRunning="True"
Color="Blue"
HorizontalOptions="Center"
VerticalOptions="Center" />
<Label Text="登录中..."
FontAttributes="Bold"
FontSize="24"
TextColor="Black"/>
</VerticalStackLayout>
</Grid>
</Grid>
</ContentPage>

14
View/LogPage.xaml.cs

@ -70,10 +70,12 @@ public partial class LogPage : ContentPage
private async void Log_Clicked(object sender, EventArgs e)//登录
{
TcpServer.Configuration(SERVERIP.Text, UsernameEntry.Text, PasswordEntry.Text,
TcpServer.Configuration(SERVERIP.Text, UsernameEntry.Text, PasswordEntry.Text,
Models.AppModels.GetAppUniqueId());
if (await AppModels.LogIn())
LoadingIndicator.IsVisible = true;
if (await AppModels.LogIn())
{
var temp_name = AppModels.Select("SELECT * FROM Users WHERE User='" + UsernameEntry.Text + "' LIMIT 1;")!.Tables[0];
if (temp_name != null)
@ -104,8 +106,14 @@ public partial class LogPage : ContentPage
App.GlobalData.ServerID + "');";
AppModels.INSERT(sql);
}
await Navigation.PopModalAsync();
}
else
{
await DisplayAlertAsync("未登录", "服务器不存在或拒绝访问", "是");
}
await Navigation.PopModalAsync();
LoadingIndicator.IsVisible = false;
}

Loading…
Cancel
Save