From 686ef24cdec654e3a88c33b038f1080379b442a2 Mon Sep 17 00:00:00 2001
From: XuShanQiXun <3401460572@qq.com>
Date: Sun, 15 Jun 2025 12:51:51 +0800
Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20chatserver=20=E9=A1=B9?=
=?UTF-8?q?=E7=9B=AE=E5=B9=B6=E6=9B=B4=E6=96=B0=E7=9B=B8=E5=85=B3=E9=85=8D?=
=?UTF-8?q?=E7=BD=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
在 `chatclient.sln` 中添加 `chatserver` 项目,配置调试和发布设置。更新 `App.config` 中 `log4net` 的配置路径。修改 `TrayIconManager.cs` 中的分隔符样式引用。更新 `chatapi.cs` 中的服务器地址和相关数据结构,增加 `userid` 和 `token` 字段。优化 `LoginWindow.xaml` 和 `MainWindow.xaml.cs` 的布局和逻辑,确保用户 ID 正确处理。更新 `log4net.config` 日志格式,添加控制台输出。配置 `chatserver.csproj` 的依赖项,添加服务器基本逻辑和消息类型枚举。更新 `launchSettings.json` 启动配置。
---
chatclient.sln | 8 +-
chatclient/App.config | 2 +-
chatclient/Data/TrayIconManager.cs | 2 +-
chatclient/Data/chatapi.cs | 18 +-
chatclient/LoginWindow.xaml | 1 -
chatclient/LoginWindow.xaml.cs | 92 ++++----
chatclient/MainWindow.xaml | 11 +-
chatclient/MainWindow.xaml.cs | 141 ++++++++----
chatclient/config/log4net.config | 2 +-
chatserver/App.config | 7 +
chatserver/Data/ChatData.cs | 16 ++
chatserver/Data/chatapi.cs | 57 +++++
chatserver/Program.cs | 264 ++++++++++++++++++++++
chatserver/Properties/launchSettings.json | 8 +
chatserver/chatserver.csproj | 26 +++
chatserver/config/log4net.config | 59 +++++
16 files changed, 609 insertions(+), 105 deletions(-)
create mode 100644 chatserver/App.config
create mode 100644 chatserver/Data/ChatData.cs
create mode 100644 chatserver/Data/chatapi.cs
create mode 100644 chatserver/Program.cs
create mode 100644 chatserver/Properties/launchSettings.json
create mode 100644 chatserver/chatserver.csproj
create mode 100644 chatserver/config/log4net.config
diff --git a/chatclient.sln b/chatclient.sln
index f12a4a1..bbc5827 100644
--- a/chatclient.sln
+++ b/chatclient.sln
@@ -1,10 +1,12 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
-VisualStudioVersion = 17.13.35931.197 d17.13
+VisualStudioVersion = 17.13.35931.197
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "chatclient", "chatclient\chatclient.csproj", "{6965B200-D0AA-4729-A5A4-30DFD307EB80}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "chatserver", "chatserver\chatserver.csproj", "{5AE823C9-2275-45F1-B312-0D1ED4237A2D}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -15,6 +17,10 @@ Global
{6965B200-D0AA-4729-A5A4-30DFD307EB80}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6965B200-D0AA-4729-A5A4-30DFD307EB80}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6965B200-D0AA-4729-A5A4-30DFD307EB80}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5AE823C9-2275-45F1-B312-0D1ED4237A2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5AE823C9-2275-45F1-B312-0D1ED4237A2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5AE823C9-2275-45F1-B312-0D1ED4237A2D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5AE823C9-2275-45F1-B312-0D1ED4237A2D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/chatclient/App.config b/chatclient/App.config
index 964a4fb..50b703a 100644
--- a/chatclient/App.config
+++ b/chatclient/App.config
@@ -3,5 +3,5 @@
-
+
\ No newline at end of file
diff --git a/chatclient/Data/TrayIconManager.cs b/chatclient/Data/TrayIconManager.cs
index f1e04dc..29c8c18 100644
--- a/chatclient/Data/TrayIconManager.cs
+++ b/chatclient/Data/TrayIconManager.cs
@@ -48,7 +48,7 @@ namespace chatclient.Data
// 添加菜单项
contextMenu.Items.Add(CreateMenuItem("打开程序", PackIconKind.WindowRestore, OpenApp_Click));
contextMenu.Items.Add(CreateMenuItem("设置", PackIconKind.Cog, Settings_Click));
- contextMenu.Items.Add(new Separator { Style = (Style)Application.Current.Resources["MaterialDesignLightSeparator"] });
+ contextMenu.Items.Add(new Separator { Style = (Style)Application.Current.Resources["Separator"] });
//contextMenu.Items.Add(CreateMenuItem("Check for Updates", PackIconKind.Update, Updates_Click));
//contextMenu.Items.Add(CreateMenuItem("Help", PackIconKind.HelpCircle, Help_Click));
//contextMenu.Items.Add(new Separator { Style = (Style)Application.Current.Resources["MaterialDesignLightSeparator"] });
diff --git a/chatclient/Data/chatapi.cs b/chatclient/Data/chatapi.cs
index aef143b..15eff90 100644
--- a/chatclient/Data/chatapi.cs
+++ b/chatclient/Data/chatapi.cs
@@ -4,9 +4,9 @@ namespace chatclient.Data
{
internal class Server
{
- public const string ServerUrl = "http://175.24.191.172:5001";
- public const string ServerIP = "175.24.191.172";
- public const int ServerPort = 8889;
+ public const string ServerUrl = "http://127.0.0.1:5001";
+ public const string ServerIP = "127.0.0.1";
+ public const int ServerPort = 52006;
}
internal class LoginData
{
@@ -21,6 +21,7 @@ namespace chatclient.Data
public string? message { get; set; }
public string? token { get; set; }
public string? username { get; set; }
+ public string? userid { get; set; } = "Unid";
}
internal class SignData
{
@@ -30,7 +31,7 @@ namespace chatclient.Data
}
internal class SignResultData
{
- public bool success { get; set; } = false;
+ public string? status { get; set; } = null;
public string? message { get; set; } = null;
}
internal class RegisterData
@@ -40,14 +41,19 @@ namespace chatclient.Data
internal class ChatRegisterData
{
public string? user { get; set; } = "Unnamed";
+ public required string userid { get; set; } = "Unid";
public string? status { get; set; } = null;
public string? message { get; set; } = null;
- public string? image { get; set; } = null;
- public DateTime timestamp { get; set; } = DateTime.Now;
+ public string? avatar { get; set; } = null;
+ public MessageType? msgtype { get; set; } = MessageType.Text;
+ public DateTime? timestamp { get; set; } = DateTime.Now;
}
internal class ChatData
{
public required string type { get; set; } = "chat";
public required string message { get; set; } = "message";
+ public MessageType? msgtype { get; set; } = MessageType.Text;
+ public required string userid { get; set; } = "Unid";
+ public string? token { get; set; } = null; // 添加token字段
}
}
diff --git a/chatclient/LoginWindow.xaml b/chatclient/LoginWindow.xaml
index 08bb72e..00c9271 100644
--- a/chatclient/LoginWindow.xaml
+++ b/chatclient/LoginWindow.xaml
@@ -9,7 +9,6 @@
mc:Ignorable="d"
Title="LoginWindow" Height="540" Width="330" MinHeight="540" MinWidth="330" MaxHeight="540" MaxWidth="330"
ResizeMode="NoResize" Closing="Window_Closing" Loaded="Window_Loaded">
-
diff --git a/chatclient/LoginWindow.xaml.cs b/chatclient/LoginWindow.xaml.cs
index b27f93a..5b1e999 100644
--- a/chatclient/LoginWindow.xaml.cs
+++ b/chatclient/LoginWindow.xaml.cs
@@ -108,14 +108,6 @@ namespace chatclient
if (Task.IsCompletedSuccessfully)
{
log.Info("注册请求发送成功");
- Application.Current.Dispatcher.Invoke(() =>
- {
- var loginWindow = Application.Current.Windows.OfType().FirstOrDefault();
- if (loginWindow != null)
- {
- loginWindow.SignMsg = "注册请求已发送,请等待服务器响应";
- }
- });
}
else
{
@@ -187,47 +179,47 @@ namespace chatclient
}
});
}
- public static async Task HttpSignRegistryUser(string Username, string Userpassword)
- {
- try
- {
- var SignData = new
- {
- type = "register",
- username = Username,
- password = Userpassword
- };
- string SignJsonData = JsonSerializer.Serialize(SignData);
- byte[] dataBytes = Encoding.UTF8.GetBytes(SignJsonData);
- var content = new StringContent(SignJsonData, Encoding.UTF8, "application/json");
- var response = await MainWindow.HttpClient.PostAsync($"{Server.ServerUrl}/api/register", content);
- var responseBody = await response.Content.ReadAsStringAsync();
- log.Info($"注册请求已发送,响应内容: {responseBody}");
- var signresponse = JsonSerializer.Deserialize(responseBody);
- if (signresponse!.success)
- {
- log.Info($"注册成功: {signresponse.message}");
- await Login(true, Username, Userpassword);
- }
- else
- {
- log.Error($"注册失败: {signresponse.message}");
- Application.Current.Dispatcher.Invoke(() =>
- {
- var loginWindow = Application.Current.Windows.OfType().FirstOrDefault();
- loginWindow!.SignMsg = signresponse.message;
- });
- }
- }
- catch (Exception ex)
- {
- log.Error("注册请求发送失败", ex);
- }
- finally
- {
- log.Info("注册请求已完成");
- }
- }
+ //public static async Task HttpSignRegistryUser(string Username, string Userpassword)
+ //{
+ // try
+ // {
+ // var SignData = new
+ // {
+ // type = "register",
+ // username = Username,
+ // password = Userpassword
+ // };
+ // string SignJsonData = JsonSerializer.Serialize(SignData);
+ // byte[] dataBytes = Encoding.UTF8.GetBytes(SignJsonData);
+ // var content = new StringContent(SignJsonData, Encoding.UTF8, "application/json");
+ // var response = await MainWindow.HttpClient.PostAsync($"{Server.ServerUrl}/api/register", content);
+ // var responseBody = await response.Content.ReadAsStringAsync();
+ // log.Info($"注册请求已发送,响应内容: {responseBody}");
+ // var signresponse = JsonSerializer.Deserialize(responseBody);
+ // if (signresponse!.status)
+ // {
+ // log.Info($"注册成功: {signresponse.message}");
+ // await Login(true, Username, Userpassword);
+ // }
+ // else
+ // {
+ // log.Error($"注册失败: {signresponse.message}");
+ // Application.Current.Dispatcher.Invoke(() =>
+ // {
+ // var loginWindow = Application.Current.Windows.OfType().FirstOrDefault();
+ // loginWindow!.SignMsg = signresponse.message;
+ // });
+ // }
+ // }
+ // catch (Exception ex)
+ // {
+ // log.Error("注册请求发送失败", ex);
+ // }
+ // finally
+ // {
+ // log.Info("注册请求已完成");
+ // }
+ // }
public static async Task Login(bool Sign, string Username, string Userpassword)
{
// 公共的登录数据准备
@@ -341,7 +333,7 @@ namespace chatclient
log.Error("保存登录信息到临时文件失败", ex);
}
}
- if (MainWindow.token == null) Application.Current.Shutdown();
+ if (MainWindow.UserId == null) Application.Current.Shutdown();
}
}
}
diff --git a/chatclient/MainWindow.xaml b/chatclient/MainWindow.xaml
index cf720da..bec1dd2 100644
--- a/chatclient/MainWindow.xaml
+++ b/chatclient/MainWindow.xaml
@@ -138,10 +138,17 @@
+
-
-
+
+
+
+
+
+
+
+
diff --git a/chatclient/MainWindow.xaml.cs b/chatclient/MainWindow.xaml.cs
index 39402fd..fbd3504 100644
--- a/chatclient/MainWindow.xaml.cs
+++ b/chatclient/MainWindow.xaml.cs
@@ -35,6 +35,7 @@ namespace chatclient
static string? receive;
public static string UserName { get; set; } = "?";
public static string? token = null;
+ public static string? UserId = null;
private static readonly ILog log = LogManager.GetLogger(typeof(MainWindow));
public static Socket? Client;
public static readonly HttpClient HttpClient = new HttpClient();
@@ -133,12 +134,13 @@ namespace chatclient
var Type = JsonSerializer.Deserialize(msg);
if (Type != null)
{
- if (Type.type == "login_1")
+ if (Type.type == "login")
{
var LoginResponse = JsonSerializer.Deserialize(msg);
- if (LoginResponse!.status == "success" && LoginResponse != null)
+ if (LoginResponse!.status == "succeed" && LoginResponse != null)
{
- token = LoginResponse.token;
+ //token = LoginResponse.token;
+ UserId = LoginResponse.userid ?? "Unid";
UserName = LoginResponse.username ?? "Unnamed";
Application.Current.Dispatcher.Invoke(() =>
{
@@ -155,7 +157,7 @@ namespace chatclient
Sender = "System",
MsgType = MessageType.System,
Image = new BitmapImage(new Uri("pack://application:,,,/resource/user.png")),
- Content = $"你好 {UserName} !",
+ Content = $"你好 {UserName} (id: {UserId} )!",
Timestamp = DateTime.Now,
Alignment = HorizontalAlignment.Center,
SenderColor = new SolidColorBrush(Colors.Gray)
@@ -163,7 +165,31 @@ namespace chatclient
mainWindow?.Messages.Add(chatmessage);
}
});
- log.Info($"用户 {UserName} 登录成功(token:{token})");
+ log.Info($"用户 {UserName} 登录成功(token:{token},userid:{UserId})");
+ }
+ else if (LoginResponse!.status == "error_0")
+ {
+ log.Warn($"登录失败: {LoginResponse!.message}\nMsg:{msg}");
+ Application.Current.Dispatcher.Invoke(() =>
+ {
+ var loginWindow = Application.Current.Windows.OfType().FirstOrDefault();
+ if (loginWindow != null)
+ {
+ loginWindow.LoginMsg = "用户名或密码错误";
+ }
+ });
+ }
+ else if (LoginResponse!.status == "error_2")
+ {
+ log.Warn($"登录失败: {LoginResponse!.message}\nMsg:{msg}");
+ Application.Current.Dispatcher.Invoke(() =>
+ {
+ var loginWindow = Application.Current.Windows.OfType().FirstOrDefault();
+ if (loginWindow != null)
+ {
+ loginWindow.LoginMsg = "用户名长度必须在2到20个字符之间";
+ }
+ });
}
else
{
@@ -177,41 +203,68 @@ namespace chatclient
});
}
}
- else if (Type.type == "login_0")
- {
- var LoginResponse = JsonSerializer.Deserialize(msg);
- log.Warn($"登录失败: {LoginResponse!.message}\nMsg:{msg}");
- Application.Current.Dispatcher.Invoke(() =>
- {
- var loginWindow = Application.Current.Windows.OfType().FirstOrDefault();
- if (loginWindow != null)
- {
- loginWindow.LoginMsg = "用户名或密码错误";
- }
- });
- }
- else if (Type.type == "register_1")
+ else if (Type.type == "register")
{
var SignResponse = JsonSerializer.Deserialize(msg);
- log.Warn($"注册成功\nMsg:{msg}");
- Application.Current.Dispatcher.Invoke(async () =>
+ if (SignResponse!.status == "success")
{
- //var loginWindow = Application.Current.Windows.OfType().FirstOrDefault();
- await LoginWindow.Login(true,LoginWindow.SignName, LoginWindow.SignPassword1);
- });
- }
- else if (Type.type == "register_0")
- {
- var SignResponse = JsonSerializer.Deserialize(msg);
- log.Warn($"注册失败: {SignResponse!.message}\nMsg:{msg}");
- Application.Current.Dispatcher.Invoke(() =>
- {
- var loginWindow = Application.Current.Windows.OfType().FirstOrDefault();
- if (loginWindow != null)
+ log.Warn($"注册成功\nMsg:{msg}");
+ Application.Current.Dispatcher.Invoke(async () =>
{
- loginWindow.SignMsg = "用户名已存在";
+ //var loginWindow = Application.Current.Windows.OfType().FirstOrDefault();
+ await LoginWindow.Login(true, LoginWindow.SignName, LoginWindow.SignPassword1);
+ });
+ }
+ else if (SignResponse!.status == "error_1")
+ {
+ log.Warn($"注册失败: {SignResponse!.message}\nMsg:{msg}");
+ Application.Current.Dispatcher.Invoke(() =>
+ {
+ var loginWindow = Application.Current.Windows.OfType().FirstOrDefault();
+ if (loginWindow != null)
+ {
+ loginWindow.SignMsg = "密码长度必须在4到20个字符之间";
+ }
+ });
+ }
+ else if (SignResponse!.status == "error_2")
+ {
+ log.Warn($"注册失败: {SignResponse!.message}\nMsg:{msg}");
+ Application.Current.Dispatcher.Invoke(() =>
+ {
+ var loginWindow = Application.Current.Windows.OfType().FirstOrDefault();
+ if (loginWindow != null)
+ {
+ loginWindow.SignMsg = "用户名长度必须在2到20个字符之间";
+ }
+ });
+ }
+ else if (SignResponse!.status == "error_3")
+ {
+ log.Warn($"注册失败: {SignResponse!.message}\nMsg:{msg}");
+ {
+ Application.Current.Dispatcher.Invoke(() =>
+ {
+ var loginWindow = Application.Current.Windows.OfType().FirstOrDefault();
+ if (loginWindow != null)
+ {
+ loginWindow.SignMsg = "用户名已存在";
+ }
+ });
}
- });
+ }
+ else
+ {
+ log.Error($"注册失败: {SignResponse!.message}\nMsg:{msg}");
+ Application.Current.Dispatcher.Invoke(() =>
+ {
+ var loginWindow = Application.Current.Windows.OfType().FirstOrDefault();
+ if (loginWindow != null)
+ {
+ loginWindow.SignMsg = SignResponse != null ? SignResponse.message : "服务器返回错误";
+ }
+ });
+ }
}
else if (Type.type == "chat")
{
@@ -221,15 +274,15 @@ namespace chatclient
Application.Current.Dispatcher.Invoke(() =>
{
// 处理聊天消息
- if (chat.user == UserName)
+ if (chat.userid == UserId)
{
var chatmessage = new ChatMessage
{
Sender = chat.user ?? "未知用户",
MsgType = MessageType.Text,
- Image = new BitmapImage(new Uri(chat.image ?? "pack://application:,,,/resource/user.png", UriKind.Absolute)),
+ Image = new BitmapImage(new Uri(chat.avatar ?? "pack://application:,,,/resource/user.png")),
Content = chat.message ?? "(无内容)",
- Timestamp = DateTime.Now,
+ Timestamp = chat.timestamp ?? DateTime.Now,
Alignment = HorizontalAlignment.Right,
SenderColor = new SolidColorBrush(Colors.Blue)
};
@@ -242,9 +295,9 @@ namespace chatclient
{
Sender = chat.user ?? "未知用户",
MsgType = MessageType.Text,
- Image = new BitmapImage(new Uri(chat.image ?? "pack://application:,,,/resource/user.png", UriKind.Absolute)),
+ Image = new BitmapImage(new Uri(chat.avatar ?? "pack://application:,,,/resource/user.png")),
Content = chat.message ?? "(无内容)",
- Timestamp = chat.timestamp,
+ Timestamp = chat.timestamp ?? DateTime.Now,
Alignment = HorizontalAlignment.Left,
SenderColor = new SolidColorBrush(Colors.Black)
};
@@ -258,6 +311,7 @@ namespace chatclient
log.Error("反序列化聊天数据时返回了 null");
}
}
+ else if (Type.type == "ping") { }
else
{
log.Error($"未知的消息类型: {Type.type},请检查服务器响应格式");
@@ -307,7 +361,10 @@ namespace chatclient
var newChatMessage = new ChatData
{
type = "chat",
- message = txtMessage.Text
+ message = txtMessage.Text,
+ msgtype = MessageType.Text,
+ userid = UserId ?? "Unid", // 使用UserId作为发送者ID
+ token = token // 添加当前token
};
string ChatJsonData = JsonSerializer.Serialize(newChatMessage);
byte[] dataBytes = Encoding.UTF8.GetBytes(ChatJsonData);
@@ -372,7 +429,7 @@ namespace chatclient
{
log.Info("MainWindow 关闭事件触发,清理资源");
// 清理资源
- Client?.Shutdown(SocketShutdown.Both);
+ if (Client!.Connected) Client?.Shutdown(SocketShutdown.Both);
Client?.Close();
log.Info("关闭Socket连接");
Client?.Dispose();
diff --git a/chatclient/config/log4net.config b/chatclient/config/log4net.config
index 346ce4c..12dfd50 100644
--- a/chatclient/config/log4net.config
+++ b/chatclient/config/log4net.config
@@ -10,7 +10,7 @@
-
+
diff --git a/chatserver/App.config b/chatserver/App.config
new file mode 100644
index 0000000..50b703a
--- /dev/null
+++ b/chatserver/App.config
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/chatserver/Data/ChatData.cs b/chatserver/Data/ChatData.cs
new file mode 100644
index 0000000..d8b49d2
--- /dev/null
+++ b/chatserver/Data/ChatData.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace chatserver.Data
+{
+ public enum MessageType
+ {
+ Text,
+ Image,//图片
+ File,//文件
+ System//系统信息
+ }
+}
diff --git a/chatserver/Data/chatapi.cs b/chatserver/Data/chatapi.cs
new file mode 100644
index 0000000..5c9e194
--- /dev/null
+++ b/chatserver/Data/chatapi.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace chatserver.Data
+{
+ internal class LoginData
+ {
+ public string? username { get; set; } = null;
+ public string? password { get; set; } = null;
+ public string? token { get; set; } = null;
+ }
+ internal class LoginResultData
+ {
+ public required string type { get; set; } = "login";
+ public string? userid { get; set; } = "Unid";
+ public string? status { get; set; }
+ public string? message { get; set; }
+ public string? token { get; set; }
+ public string? username { get; set; }
+ }
+ internal class SignData
+ {
+ public string? username { get; set; } = null;
+ public string? password { get; set; } = null;
+ }
+ internal class SignResultData
+ {
+ public required string type { get; set; } = "sign";
+ public string? status { get; set; } = null;
+ public string? message { get; set; } = null;
+ }
+ internal class TypeData
+ {
+ public string? type { get; set; }
+ }
+ internal class ChatRegisterData
+ {
+ public required string type { get; set; } = "chat";
+ public required string userid { get; set; } = "Unid";
+ public string user { get; set; } = "Unnamed";
+ public string? status { get; set; } = null;
+ public string? message { get; set; } = null;
+ public string? avatar { get; set; } = null;
+ public MessageType? msgtype { get; set; } = MessageType.Text;
+ public DateTime? timestamp { get; set; } = DateTime.Now;
+ }
+ internal class ChatData
+ {
+ public required string message { get; set; } = "message";
+ public MessageType? msgtype { get; set; } = MessageType.Text;
+ public required string userid { get; set; } = "Unid";
+ public string? token { get; set; } = null; // 添加token字段
+ }
+}
diff --git a/chatserver/Program.cs b/chatserver/Program.cs
new file mode 100644
index 0000000..650591f
--- /dev/null
+++ b/chatserver/Program.cs
@@ -0,0 +1,264 @@
+using System.Net.Sockets;
+using System.Net.Http;
+using log4net;
+using log4net.Config;
+using System.Net;
+using System.Data.SQLite;
+using chatserver.Data;
+using System.Text.Json;
+using System.Reflection;
+
+[assembly: XmlConfigurator(ConfigFile = "config/log4net.config", Watch = true)]
+namespace chatserver
+{
+ internal class ChatServer
+ {
+ private static readonly ILog log = LogManager.GetLogger(typeof(ChatServer));
+ private static List Client = new();
+ private static List token = new();
+ private static Socket? Server;
+ private static SQLiteConnection? User_db;
+
+ static void Main(string[] args)
+ {
+ //XmlConfigurator.Configure();
+ log.Info("Hello World!");
+ Server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+ Server.Bind(new IPEndPoint(IPAddress.Any, 52006));
+ Server.Listen(20);
+ OpenUser_db();
+ log.Info("服务器以在52006端口监听");
+ while (true)
+ {
+ try
+ {
+ Socket client = Server.Accept();
+ Client.Add(client);
+ log.Info($"用户{client.RemoteEndPoint}连接");
+ Thread thread = new Thread(() => HandleClient(client));
+ thread.Start();
+ }
+ catch (Exception ex)
+ {
+ log.Error("Error accepting client connection: " + ex.Message);
+ }
+ }
+ }
+ public static void OpenUser_db()
+ {
+ log.Info("正在打开数据库连接...");
+ User_db = new SQLiteConnection("Data Source=ServerUser.db;Version=3;"); //没有数据库则自动创建
+ User_db.Open();
+ EnsureUsersTableExists(); // 确保users表存在
+ log.Info("数据库连接已打开");
+ }
+ static void HandleClient(Socket socket)
+ {
+ try
+ {
+ while (true)
+
+ {
+ byte[] buffer = new byte[1024];
+ int received = socket.Receive(buffer);
+ if (received == 0) break; // 客户端断开连接
+ string message = System.Text.Encoding.UTF8.GetString(buffer, 0, received);
+ log.Info("Received message: " + message);
+ var Type = JsonSerializer.Deserialize(message);
+ if (Type != null)
+ {
+ if (Type.type == "register")
+ {
+ var sginuser = JsonSerializer.Deserialize(message);
+ if (sginuser != null && sginuser.username != null && sginuser.password != null)
+ {
+ log.Info($"用户 {sginuser.username} 正在注册");
+ if (string.IsNullOrEmpty(sginuser.username) || string.IsNullOrEmpty(sginuser.password))
+ {
+ log.Warn("用户名或密码不能为空");
+ var emptyResult = new SignResultData { type = "register", status = "error_-1", message = "用户名或密码不能为空" };
+ socket.Send(JsonSerializer.SerializeToUtf8Bytes(emptyResult));
+ continue; // 如果用户名或密码为空,则跳过注册流程
+ }
+ if (sginuser.username.Length < 2 || sginuser.username.Length > 20)
+ {
+ log.Warn($"用户注册时 {sginuser.username} 用户名长度不符合要求");
+ var lengthResult = new SignResultData { type = "register", status = "error_2", message = "用户名长度必须在2到20个字符之间" };
+ socket.Send(JsonSerializer.SerializeToUtf8Bytes(lengthResult));
+ continue; // 如果用户名长度不符合要求,则跳过注册流程
+ }
+ if (sginuser.password.Length < 4 || sginuser.password.Length > 20)
+ {
+ log.Warn($"用户注册时 {sginuser.username} 密码长度不符合要求");
+ var weakPwdResult = new SignResultData { type = "register", status = "error_1", message = "密码长度必须在4到20个字符之间" };
+ socket.Send(JsonSerializer.SerializeToUtf8Bytes(weakPwdResult));
+ continue; // 如果密码过弱,则跳过注册流程
+ }
+ if (UserExists(sginuser.username))
+ {
+ log.Warn($"用户 {sginuser.username} 已存在");
+ var Result = new SignResultData { type = "register", status = "error_0", message = "用户名已存在" };
+ socket.Send(System.Text.Encoding.UTF8.GetBytes(JsonSerializer.Serialize(Result)));
+ continue;// 如果用户名已存在,则跳过注册流程
+ }
+ var cmd = new SQLiteCommand("INSERT INTO users (userid, username, password) VALUES (@userid, @username, @password)", User_db);
+ var timedUlid = Ulid.NewUlid(DateTimeOffset.UtcNow);
+ cmd.Parameters.AddWithValue("@userid", timedUlid);
+ cmd.Parameters.AddWithValue("@username", sginuser.username);
+ cmd.Parameters.AddWithValue("@password", sginuser.password);
+ cmd.ExecuteNonQuery();
+ log.Info($"用户 {sginuser.username} 注册成功(id:{timedUlid})");
+ var result = new SignResultData { type = "register", status = "succeed", message = "注册成功" };
+ socket.Send(System.Text.Encoding.UTF8.GetBytes(JsonSerializer.Serialize(result)));
+ }
+ }
+ else if (Type.type == "login")
+ {
+ var loginData = JsonSerializer.Deserialize(message);
+ if (loginData != null)
+ {
+ if (string.IsNullOrEmpty(loginData.username) || string.IsNullOrEmpty(loginData.password))
+ {
+ log.Warn("用户名或密码不能为空");
+ var emptyResult = new LoginResultData { type = "login", status = "error_-1", message = "用户名或密码不能为空" };
+ socket.Send(JsonSerializer.SerializeToUtf8Bytes(emptyResult));
+ continue; // 如果用户名或密码为空,则跳过登录流程
+ }
+ if (loginData.username.Length < 2 || loginData.username.Length > 20)
+ {
+ log.Warn($"用户登录时 {loginData.username} 用户名长度不符合要求");
+ var lengthResult = new LoginResultData { type = "login", status = "error_2", message = "用户名长度必须在2到20个字符之间" };
+ socket.Send(JsonSerializer.SerializeToUtf8Bytes(lengthResult));
+ continue; // 如果用户名长度不符合要求,则跳过登录流程
+ }
+ var Authentication = UserAuthentication(loginData.username, loginData.password);
+ if (Authentication != "")
+ {
+ log.Info($"用户 {loginData.username} 登录成功 (id:{Authentication})");
+ var result = new LoginResultData
+ {
+ type = "login",
+ status = "succeed",
+ message = "登录成功",
+ //token = Authentication,
+ username = loginData.username,
+ userid = Authentication
+ };
+ socket.Send(System.Text.Encoding.UTF8.GetBytes(JsonSerializer.Serialize(result)));
+ }
+ else
+ {
+ log.Warn($"用户 {loginData.username} 登录失败,用户名或密码错误");
+ var result = new LoginResultData { type = "login", status = "error_0", message = "用户名或密码错误" };
+ socket.Send(System.Text.Encoding.UTF8.GetBytes(JsonSerializer.Serialize(result)));
+ }
+ }
+ }
+ else if (Type.type == "chat")
+ {
+ var chatData = JsonSerializer.Deserialize(message);
+ if (chatData != null && chatData.message != null)
+ {
+ log.Info($"接收到聊天消息: {chatData.message}");
+ var chatRegisterData = new ChatRegisterData
+ {
+ type = "chat",
+ userid = chatData.userid ?? "Unid",
+ user = GetUsernameByUserId(chatData.userid!),
+ message = chatData.message,
+ msgtype = chatData.msgtype ?? MessageType.Text,
+ // 替换为
+ timestamp = DateTime.Now
+ };
+ foreach (var client in Client)
+ {
+ client.Send(System.Text.Encoding.UTF8.GetBytes(JsonSerializer.Serialize(chatRegisterData)));
+ }
+ }
+ else
+ {
+ log.Warn("接收到无效的聊天消息");
+ }
+ }
+ else
+ {
+ log.Warn("未知的请求类型: " + Type.type);
+ }
+ }
+ }
+ }
+ catch (SocketException ex)
+ {
+ log.Error("Socket error: " + ex.Message);
+ }
+ catch (JsonException ex)
+ {
+ log.Error("JSON parsing error: " + ex.Message);
+ }
+ catch (Exception ex)
+ {
+ log.Error("Error handling client: " + ex.Message);
+ }
+ finally
+ {
+ log.Info($"用户{socket.RemoteEndPoint}已断开连接");
+ socket.Close();
+ Client.Remove(socket);
+ }
+ }
+ ///
+ /// 查询User_db是否有相同用户名
+ ///
+ ///
+ ///
+ static bool UserExists(string username)
+ {
+ using var cmd = new SQLiteCommand("SELECT COUNT(*) FROM users WHERE username = @username", User_db);
+ cmd.Parameters.AddWithValue("@username", username);
+ var count = Convert.ToInt32(cmd.ExecuteScalar());
+ return count > 0;
+ }
+ ///
+ /// 验证用户登录信息并返回userid结果
+ ///
+ ///
+ ///
+ ///
+ static string UserAuthentication(string username, string password)
+ {
+ using var cmd = new SQLiteCommand("SELECT userid FROM users WHERE username = @username AND password = @password", User_db);
+ cmd.Parameters.AddWithValue("@username", username);
+ cmd.Parameters.AddWithValue("@password", password);
+ var result = cmd.ExecuteScalar();
+ return result != null ? result.ToString()! : string.Empty;
+ }
+ // 在ChatServer类中添加一个方法用于初始化users表
+ private static void EnsureUsersTableExists()
+ {
+ using var cmd = new SQLiteCommand(@"
+ CREATE TABLE IF NOT EXISTS users (
+ userid TEXT PRIMARY KEY,
+ username TEXT NOT NULL UNIQUE,
+ password TEXT NOT NULL
+ )", User_db);
+ cmd.ExecuteNonQuery();
+ }
+ ///
+ /// 根据userid查询对应的用户名
+ ///
+ ///
+ /// 用户名,如果不存在则返回
+ static string GetUsernameByUserId(string userid)
+ {
+ if (string.IsNullOrEmpty(userid) || userid == "Unid")
+ {
+ return "Unnamed"; // 如果userid为空或为"Unid",返回默认用户名
+ }
+ using var cmd = new SQLiteCommand("SELECT username FROM users WHERE userid = @userid", User_db);
+ cmd.Parameters.AddWithValue("@userid", userid);
+ var result = cmd.ExecuteScalar();
+ return result != null ? result.ToString()! : "Unnamed";
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/chatserver/Properties/launchSettings.json b/chatserver/Properties/launchSettings.json
new file mode 100644
index 0000000..f19cb4e
--- /dev/null
+++ b/chatserver/Properties/launchSettings.json
@@ -0,0 +1,8 @@
+{
+ "profiles": {
+ "chatserver": {
+ "commandName": "Project",
+ "sqlDebugging": false
+ }
+ }
+}
\ No newline at end of file
diff --git a/chatserver/chatserver.csproj b/chatserver/chatserver.csproj
new file mode 100644
index 0000000..21e5310
--- /dev/null
+++ b/chatserver/chatserver.csproj
@@ -0,0 +1,26 @@
+
+
+
+ Exe
+ net8.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+
+
+
+
+
+
+
+
diff --git a/chatserver/config/log4net.config b/chatserver/config/log4net.config
new file mode 100644
index 0000000..ab28e9f
--- /dev/null
+++ b/chatserver/config/log4net.config
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file