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"; } } }