-
Notifications
You must be signed in to change notification settings - Fork 0
Added #53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Added #53
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| namespace ConsoleNetChat; | ||
|
|
||
| /// <summary> | ||
| /// Represents asynchronous console | ||
| /// </summary> | ||
| public static class AsyncConsole | ||
| { | ||
| private static readonly Mutex ConsoleMutex = new (); | ||
|
|
||
| /// <summary> | ||
| /// Async version of Console.WriteLine | ||
| /// </summary> | ||
| /// <param name="message">Message to write</param> | ||
| public static void WriteLine(string message) | ||
| { | ||
| ConsoleMutex.WaitOne(); | ||
| Console.WriteLine(message); | ||
| ConsoleMutex.ReleaseMutex(); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Async version of Console.Write | ||
| /// </summary> | ||
| /// <param name="message">Message to write</param> | ||
| public static void Write(string message) | ||
| { | ||
| ConsoleMutex.WaitOne(); | ||
| Console.Write(message); | ||
| ConsoleMutex.ReleaseMutex(); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,95 @@ | ||||||||||||||
| using System.Net.Sockets; | ||||||||||||||
| using System.Net; | ||||||||||||||
| using System.Net.NetworkInformation; | ||||||||||||||
|
|
||||||||||||||
| namespace ConsoleNetChat; | ||||||||||||||
|
|
||||||||||||||
| /// <summary> | ||||||||||||||
| /// Class for chat member | ||||||||||||||
| /// </summary> | ||||||||||||||
| public class Chatter | ||||||||||||||
| { | ||||||||||||||
| protected TcpClient Client = new (); | ||||||||||||||
| protected StreamWriter? Writer; | ||||||||||||||
|
Comment on lines
+12
to
+13
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||||||||||
|
|
||||||||||||||
| /// <summary> | ||||||||||||||
| /// Sends message into chat | ||||||||||||||
| /// </summary> | ||||||||||||||
| /// <param name="message">Message to send</param> | ||||||||||||||
| /// <exception cref="ChatterException">If connection is close</exception> | ||||||||||||||
| public async Task SendMessage(string message) | ||||||||||||||
| { | ||||||||||||||
| if (Writer == null) | ||||||||||||||
| { | ||||||||||||||
| throw new ChatterException("Not started"); | ||||||||||||||
| } | ||||||||||||||
| await Writer.WriteLineAsync(message); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| private static async Task HandleClient(TcpClient client) | ||||||||||||||
| { | ||||||||||||||
| using var reader = new StreamReader(client.GetStream()); | ||||||||||||||
|
|
||||||||||||||
| while (IsConnected(client)) | ||||||||||||||
| { | ||||||||||||||
| try | ||||||||||||||
| { | ||||||||||||||
| var data = await reader.ReadLineAsync(); | ||||||||||||||
| if (string.IsNullOrEmpty(data)) | ||||||||||||||
| { | ||||||||||||||
| continue; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| AsyncConsole.Write($"External: {data}\n"); | ||||||||||||||
| } | ||||||||||||||
| catch (Exception e) when (e is ArgumentOutOfRangeException or ObjectDisposedException or InvalidOperationException) | ||||||||||||||
| { | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| AsyncConsole.WriteLine("Disconnected"); | ||||||||||||||
| Environment.Exit(0); | ||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Не используйте Environment.Exit, это делает код непереиспользуемым, если надо выйти из чата, не убивая весь процесс, в котором он находится |
||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| private static bool IsConnected(TcpClient client) | ||||||||||||||
| { | ||||||||||||||
| return GetState(client) == TcpState.Established; | ||||||||||||||
| } | ||||||||||||||
|
Comment on lines
+54
to
+57
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
|
|
||||||||||||||
| private static TcpState GetState(TcpClient tcpClient) | ||||||||||||||
| { | ||||||||||||||
| try | ||||||||||||||
| { | ||||||||||||||
| var connectionInfo = IPGlobalProperties.GetIPGlobalProperties() | ||||||||||||||
| .GetActiveTcpConnections() | ||||||||||||||
| .SingleOrDefault(x => x.LocalEndPoint.Equals(tcpClient.Client.LocalEndPoint)); | ||||||||||||||
| return connectionInfo?.State ?? TcpState.Unknown; | ||||||||||||||
| } | ||||||||||||||
| catch (ObjectDisposedException) | ||||||||||||||
| { | ||||||||||||||
| return TcpState.Closed; | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| /// <summary> | ||||||||||||||
| /// Finishes the chat | ||||||||||||||
| /// </summary> | ||||||||||||||
| public void Disconnect() | ||||||||||||||
| { | ||||||||||||||
| Client.Close(); | ||||||||||||||
| AsyncConsole.WriteLine("Disconnected"); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| /// <summary> | ||||||||||||||
| /// Listens for external messages | ||||||||||||||
| /// </summary> | ||||||||||||||
| /// <exception cref="ChatterException">If connection is closed</exception> | ||||||||||||||
| public async Task Listen() | ||||||||||||||
| { | ||||||||||||||
| if (!IsConnected(Client)) | ||||||||||||||
| { | ||||||||||||||
| throw new ChatterException("Cant listen: no connection"); | ||||||||||||||
| } | ||||||||||||||
| await HandleClient(Client); | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| namespace ConsoleNetChat; | ||
|
|
||
| public class ChatterException : Exception | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Надо тоже комментарий |
||
| { | ||
| public ChatterException() | ||
| { | ||
| } | ||
|
|
||
| public ChatterException(string message) : base(message) | ||
| { | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| using System.Net; | ||
| using System.Net.Sockets; | ||
|
|
||
| namespace ConsoleNetChat; | ||
|
|
||
| /// <summary> | ||
| /// Represents chat client | ||
| /// </summary> | ||
| public class Client : Chatter | ||
| { | ||
| /// <summary> | ||
| /// Connects to the server | ||
| /// </summary> | ||
| /// <param name="addr">Server address</param> | ||
| /// <param name="port">Server port</param> | ||
| /// <exception cref="ChatterException">If error occured(e.g. no server on that address</exception> | ||
| public async Task Connect(IPAddress addr, int port) | ||
| { | ||
| try | ||
| { | ||
| await Client.ConnectAsync(addr, port); | ||
| } | ||
| catch (Exception e) when (e is ArgumentNullException or ArgumentOutOfRangeException or SocketException or ObjectDisposedException) | ||
| { | ||
| throw new ChatterException("Connection impossible"); | ||
| } | ||
|
|
||
| Writer = new StreamWriter(Client.GetStream()); | ||
| Writer.AutoFlush = true; | ||
| AsyncConsole.WriteLine("Connected"); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
|
|
||
| <PropertyGroup> | ||
| <OutputType>Exe</OutputType> | ||
| <TargetFramework>net6.0</TargetFramework> | ||
| <ImplicitUsings>enable</ImplicitUsings> | ||
| <Nullable>enable</Nullable> | ||
| </PropertyGroup> | ||
|
|
||
| </Project> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,110 @@ | ||
| using System.Net; | ||
| using ConsoleNetChat; | ||
|
|
||
| switch (args.Length) | ||
| { | ||
| case < 1 or > 2: | ||
| AsyncConsole.WriteLine("Incorrect arguments"); | ||
| return; | ||
| case 1: | ||
| { | ||
| if (!int.TryParse(args[0], out var port)) | ||
| { | ||
| AsyncConsole.WriteLine("Incorrect port"); | ||
| return; | ||
| } | ||
|
|
||
| var server = new Server(); | ||
| try | ||
| { | ||
| await server.Connect(port); | ||
| } | ||
| catch (ChatterException e) | ||
| { | ||
| AsyncConsole.WriteLine(e.Message); | ||
| return; | ||
| } | ||
|
|
||
| try | ||
| { | ||
| #pragma warning disable CS4014 // This is started in background thread | ||
| server.Listen(); | ||
| #pragma warning restore CS4014 // This is started in background thread | ||
| } | ||
| catch (ChatterException e) | ||
| { | ||
| AsyncConsole.WriteLine(e.Message); | ||
| return; | ||
| } | ||
|
|
||
| while (true) | ||
| { | ||
| var message = Console.ReadLine(); | ||
| if (string.IsNullOrEmpty(message)) | ||
| { | ||
| continue; | ||
| } | ||
| await server.SendMessage(message); | ||
| if (message == "exit") | ||
| { | ||
| server.Disconnect(); | ||
| return; | ||
| } | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Архитектурно ужасно, что этот код в Main-е :) |
||
|
|
||
| break; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Компилятор выдаёт предупреждение, что выше while (true) с return, так что управление сюда никогда не попадёт |
||
| } | ||
| default: | ||
| { | ||
| if (!int.TryParse(args[1], out var port)) | ||
| { | ||
| AsyncConsole.WriteLine("Incorrect port"); | ||
| return; | ||
| } | ||
| if (!IPAddress.TryParse(args[0], out var addr)) | ||
| { | ||
| AsyncConsole.WriteLine("Incorrect address"); | ||
| return; | ||
| } | ||
|
|
||
| var client = new Client(); | ||
| try | ||
| { | ||
| await client.Connect(addr, port); | ||
| } | ||
| catch (ChatterException e) | ||
| { | ||
| AsyncConsole.WriteLine(e.Message); | ||
| return; | ||
| } | ||
|
|
||
| try | ||
| { | ||
| #pragma warning disable CS4014 // This is started in background thread | ||
| client.Listen(); | ||
| #pragma warning restore CS4014 // This is started in background thread | ||
| } | ||
| catch (ChatterException e) | ||
| { | ||
| AsyncConsole.WriteLine(e.Message); | ||
| return; | ||
| } | ||
|
|
||
| while (true) | ||
| { | ||
| var message = Console.ReadLine(); | ||
| if (string.IsNullOrEmpty(message)) | ||
| { | ||
| continue; | ||
| } | ||
| await client.SendMessage(message); | ||
| if (message == "exit") | ||
| { | ||
| client.Disconnect(); | ||
| return; | ||
| } | ||
| } | ||
|
|
||
| break; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| using System.Diagnostics; | ||
| using System.Net; | ||
| using System.Net.NetworkInformation; | ||
| using System.Net.Sockets; | ||
|
|
||
| namespace ConsoleNetChat; | ||
|
|
||
| /// <summary> | ||
| /// Represents chat server | ||
| /// </summary> | ||
| public class Server : Chatter | ||
| { | ||
| private TcpListener? _listener; | ||
|
|
||
| /// <summary> | ||
| /// Waits for chat client | ||
| /// </summary> | ||
| /// <param name="port">Port to open connection onto</param> | ||
| /// <exception cref="ChatterException">If error occured(e.g. port was occupied)</exception> | ||
| public async Task Connect(int port) | ||
| { | ||
| try | ||
| { | ||
| _listener = new TcpListener(IPAddress.Any, port); | ||
| _listener.Start(); | ||
| Client = await _listener.AcceptTcpClientAsync(); | ||
| } | ||
| catch (Exception e) when (e is ArgumentNullException or ArgumentOutOfRangeException or SocketException or InvalidOperationException) | ||
| { | ||
| throw new ChatterException("Connection interrupted"); | ||
| } | ||
| Writer = new StreamWriter(Client.GetStream()); | ||
| Writer.AutoFlush = true; | ||
| AsyncConsole.WriteLine("Connected"); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Консоль сама буквально это и делает :) AsyncConsole не нужен