diff --git a/Client/Client.csproj b/Client/Client.csproj index 52ca3d7..5198609 100644 --- a/Client/Client.csproj +++ b/Client/Client.csproj @@ -1,19 +1,24 @@ - - Exe - net8.0 - enable - true - ChatRoom - 聊天室 - ../Icon/favicon.ico - true - + + Exe + net8.0 + enable + enable + true + ChatRoom + 聊天室 + ../Icon/favicon.ico + true + - - - - + + none + + + + + + diff --git a/Client/Program.cs b/Client/Program.cs index e26389e..34df003 100644 --- a/Client/Program.cs +++ b/Client/Program.cs @@ -8,15 +8,15 @@ namespace ChatRoom; -internal class Client +internal static class Client { - internal static string UserName { get; set; } + internal static string? UserName { get; set; } private static async Task Main(string[] args) { - Option multiOption = new(name: "--multi", description: "允许重复运行实例。"); + Option multiOption = new("--multi", "允许重复运行实例。"); RootCommand rootCommand = [multiOption]; - rootCommand.SetHandler(async (multi) => + rootCommand.SetHandler(async multi => { // 进程互斥 using Mutex _ = new(true, Assembly.GetExecutingAssembly().GetName().Name, out bool isNotRunning); @@ -24,6 +24,7 @@ private static async Task Main(string[] args) { throw new EntryPointNotFoundException("你只能同时运行一个聊天室实例!"); } + await ChatMainAsync(); }, multiOption); return await rootCommand.InvokeAsync(args); @@ -39,7 +40,7 @@ private static async Task ChatMainAsync() ILogger logger = factory.CreateLogger("聊天室"); Console.Title = "聊天室"; Socket client; - string ip; + string? ip; while (true) { client = new(SocketType.Stream, ProtocolType.Tcp); @@ -47,20 +48,23 @@ private static async Task ChatMainAsync() ip = Console.ReadLine(); try { - await client.ConnectAsync(IPAddress.TryParse(ip, out IPAddress address) ? address : IPAddress.Loopback, 19132); + await client.ConnectAsync(IPAddress.TryParse(ip, out IPAddress? address) ? address : IPAddress.Loopback, + 19132); } catch (SocketException ex) { logger.LogError("连接失败:{Message}", ex.Message); continue; } + break; } + Console.Title = $"聊天室:{ip}"; Dictionary lastMessage = []; int lastOne = 0; Console.Clear(); - ThreadPool.QueueUserWorkItem(async (_) => + _ = Task.Factory.StartNew(_ => { while (true) { @@ -74,6 +78,7 @@ private static async Task ChatMainAsync() { continue; } + BinaryReader reader = new(stream); uuid = reader.ReadInt32(); ticks = reader.ReadInt64(); @@ -88,25 +93,32 @@ private static async Task ChatMainAsync() client = new(SocketType.Stream, ProtocolType.Tcp); try { - await client.ConnectAsync(IPAddress.TryParse(ip, out IPAddress address) ? address : IPAddress.Loopback, 19132); + client.ConnectAsync( + IPAddress.TryParse(ip, out IPAddress? address) ? address : IPAddress.Loopback, + 19132) + .Wait(); } catch (SocketException) { } } + logger.LogInformation("连接已恢复"); continue; } - if (lastMessage.TryGetValue(uuid, out string value) && value == message) + + if (lastMessage.TryGetValue(uuid, out string? value) && value == message) { continue; } + ConsoleColor temp = Console.ForegroundColor; Console.ForegroundColor = ConsoleColor.Blue; if (uuid != lastOne) { Console.Write($"{userName}({uuid}) "); } + Console.WriteLine(new DateTime(ticks)); Console.ForegroundColor = ConsoleColor.DarkGray; Console.WriteLine(message); @@ -114,15 +126,16 @@ private static async Task ChatMainAsync() lastMessage[uuid] = message; lastOne = uuid; } - }); + }, TaskCreationOptions.LongRunning); logger.LogInformation("连接已建立"); while (true) { - string line = Console.ReadLine(); + string? line = Console.ReadLine(); if (string.IsNullOrEmpty(line) || !client.Connected) { continue; } + if (line.StartsWith('/')) { try @@ -133,16 +146,19 @@ private static async Task ChatMainAsync() { logger.LogError("命令运行失败:{Message}", ex.Message); } + continue; } + NetworkStream stream = new(client); if (!stream.CanWrite) { continue; } + BinaryWriter writer = new(stream); writer.Write(line); writer.Write(UserName ?? string.Empty); } } -} +} \ No newline at end of file diff --git a/Client/Utils/CommandHelper.cs b/Client/Utils/CommandHelper.cs index 362a929..91bfb01 100644 --- a/Client/Utils/CommandHelper.cs +++ b/Client/Utils/CommandHelper.cs @@ -10,14 +10,14 @@ internal static class CommandHelper Action = args => { Dictionary commands = Commands; - foreach (string arg in args) + foreach (Dictionary? subcommands in (from arg in args + where commands.ContainsKey(arg.ToUpper()) + select commands[arg.ToUpper()].SubCommands) + .TakeWhile(subcommands => subcommands is not null)) { - if ((!commands.ContainsKey(arg.ToUpper())) || (commands[arg.ToUpper()].SubCommands is null)) - { - continue; - } - commands = commands[arg.ToUpper()].SubCommands; + commands = subcommands; } + foreach ((string command, CommandData commandData) in commands) { Console.WriteLine($" {command.ToLower()}\t{commandData.Description}"); @@ -38,45 +38,60 @@ internal static class CommandHelper { throw new ArgumentException("参数数量错误"); } + Client.UserName = args[0]; } } } } }; + internal static void Process(IList args, Dictionary commands, int deep = 1) { - string mainCommand = args[deep - 1].ToUpper(); - if (!commands.TryGetValue(mainCommand, out CommandData command)) - { - throw new ArgumentException($"未知的命令:{args[deep - 1]}"); - } - if (command.Action is not null) + while (true) { - List newArgs = new(args); - if (args.Count - deep > 0) + string mainCommand = args[deep - 1].ToUpper(); + if (!commands.TryGetValue(mainCommand, out CommandData command)) { - newArgs.RemoveRange(0, deep); + throw new ArgumentException($"未知的命令:{args[deep - 1]}"); } - command.Action(newArgs); - } - if (command.SubCommands is not null) - { - if (args.Count <= deep) + + if (command.Action is not null) { - foreach ((string commandName, CommandData commandData) in command.SubCommands) + List newArgs = [..args]; + if (args.Count - deep > 0) { - Console.WriteLine($" {commandName.ToLower()}\t{commandData.Description}"); + newArgs.RemoveRange(0, deep); } - return; + + command.Action(newArgs); } - Process(args, command.SubCommands, deep + 1); + + if (command.SubCommands is not null) + { + if (args.Count <= deep) + { + foreach ((string commandName, CommandData commandData) in command.SubCommands) + { + Console.WriteLine($" {commandName.ToLower()}\t{commandData.Description}"); + } + + return; + } + + commands = command.SubCommands; + ++deep; + continue; + } + + break; } } } + internal record struct CommandData { - public string Description { get; set; } - public Action> Action { get; set; } - public Dictionary SubCommands { get; set; } -} + public string Description { get; init; } + public Action>? Action { get; init; } + public Dictionary? SubCommands { get; init; } +} \ No newline at end of file diff --git a/Server/Program.cs b/Server/Program.cs index c788100..8fee661 100644 --- a/Server/Program.cs +++ b/Server/Program.cs @@ -2,14 +2,14 @@ using System.Net.Sockets; List clients = []; -using Socket listenner = new(SocketType.Stream, ProtocolType.Tcp); -listenner.Bind(new IPEndPoint(IPAddress.Any, 19132)); -listenner.Listen(); +using Socket listener = new(SocketType.Stream, ProtocolType.Tcp); +listener.Bind(new IPEndPoint(IPAddress.Any, 19132)); +listener.Listen(); while (true) { - Socket client = await listenner.AcceptAsync(); + Socket client = await listener.AcceptAsync(); clients.Add(client); - ThreadPool.QueueUserWorkItem((_) => + await Task.Factory.StartNew(_ => { while (true) { @@ -21,6 +21,7 @@ { continue; } + BinaryReader reader = new(stream); message = reader.ReadString(); userName = reader.ReadString(); @@ -30,6 +31,7 @@ clients.Remove(client); return; } + foreach (Socket otherClient in clients) { try @@ -39,8 +41,25 @@ { continue; } + BinaryWriter writer = new(stream); - writer.Write(client.RemoteEndPoint.ToString()[..client.RemoteEndPoint.ToString().LastIndexOf(':')].GetHashCode()); + if (client.RemoteEndPoint is not null) + { + string? ip = client.RemoteEndPoint.ToString(); + if (!string.IsNullOrWhiteSpace(ip)) + { + writer.Write(ip[..ip.LastIndexOf(':')].GetHashCode()); + } + else + { + writer.Write(Convert.ToInt32(client.Handle).ToString()); + } + } + else + { + writer.Write(Convert.ToInt32(client.Handle).ToString()); + } + writer.Write(DateTime.Now.Ticks); writer.Write(message); writer.Write(userName); @@ -48,9 +67,8 @@ catch (IOException) { clients.Remove(client); - continue; } } } - }); -} + }, TaskContinuationOptions.LongRunning); +} \ No newline at end of file diff --git a/Server/Server.csproj b/Server/Server.csproj index 1a99ace..678e8dc 100644 --- a/Server/Server.csproj +++ b/Server/Server.csproj @@ -1,13 +1,18 @@ - - Exe - net8.0 - enable - true - ChatRoom - ChatRoom.$(MSBuildProjectName) - true - + + Exe + net8.0 + enable + enable + true + ChatRoom + ChatRoom.$(MSBuildProjectName) + true + + + + none +