diff --git a/WebChat/WebChat.sln b/WebChat/WebChat.sln new file mode 100644 index 0000000..3db5de5 --- /dev/null +++ b/WebChat/WebChat.sln @@ -0,0 +1,16 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebChat", "WebChat\WebChat.csproj", "{26C3FA72-8E5F-42C8-BDB0-3BE8CF16BD14}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {26C3FA72-8E5F-42C8-BDB0-3BE8CF16BD14}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {26C3FA72-8E5F-42C8-BDB0-3BE8CF16BD14}.Debug|Any CPU.Build.0 = Debug|Any CPU + {26C3FA72-8E5F-42C8-BDB0-3BE8CF16BD14}.Release|Any CPU.ActiveCfg = Release|Any CPU + {26C3FA72-8E5F-42C8-BDB0-3BE8CF16BD14}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/WebChat/WebChat/Client.cs b/WebChat/WebChat/Client.cs new file mode 100644 index 0000000..5a093b4 --- /dev/null +++ b/WebChat/WebChat/Client.cs @@ -0,0 +1,53 @@ +namespace WebChat; + +using System.Net.Sockets; + +/// +/// Chat client. +/// +public class Client : IDisposable +{ + private readonly TcpClient _client; + + private readonly NetworkStream _networkStream; + + /// + /// Initializes a new instance of the class. + /// + public Client(string host, int port) + { + _client = new TcpClient(host, port); + + _networkStream = _client.GetStream(); + } + + /// + /// Gets a value indicating whether the client is disposed. + /// + public bool IsDisposed { get; private set; } + + /// + /// Releases all resources used by the current instance of the class. + /// + public void Dispose() + { + if (IsDisposed) + { + return; + } + + _networkStream.Dispose(); + _client.Dispose(); + + IsDisposed = true; + } + + /// + /// Runs client. + /// + public async Task RunAsync() + { + await Processing.ProcessQuery(_networkStream); + } + +} diff --git a/WebChat/WebChat/Processing.cs b/WebChat/WebChat/Processing.cs new file mode 100644 index 0000000..90056cb --- /dev/null +++ b/WebChat/WebChat/Processing.cs @@ -0,0 +1,45 @@ +namespace WebChat; + +using System.Net.Sockets; + +/// +/// Class for processing get and post queries. +/// +public static class Processing +{ + /// + /// Processes get and post queries. + /// + /// Working stream. + public static async Task ProcessQuery(NetworkStream stream) + { + await Task.Run(async () => await Post(stream)); + await Task.Run(async () => await Get(stream)); + } + + private static async Task Post(NetworkStream stream) + { + while (true) + { + var writer = new StreamWriter(stream); + var message = Console.ReadLine(); + await writer.WriteAsync(message); + await writer.FlushAsync(); + await stream.FlushAsync(); + + writer = null; + } + } + + private static async Task Get(NetworkStream stream) + { + while (true) + { + var reader = new StreamReader(stream); + var message = await reader.ReadLineAsync(); + Console.WriteLine(message); + + reader = null; + } + } +} diff --git a/WebChat/WebChat/Program.cs b/WebChat/WebChat/Program.cs new file mode 100644 index 0000000..6112162 --- /dev/null +++ b/WebChat/WebChat/Program.cs @@ -0,0 +1,43 @@ +using WebChat; + +switch (args.Length) +{ + case 1: + { + await StartServer(args); + break; + } + + case 2: + { + await StartClient(args); + break; + } + + default: + { + throw new ArgumentException(); + } +} + +async Task StartClient(string[] args) +{ + if (!int.TryParse(args[1], out var port)) + { + throw new ArgumentException(); + } + + using var client = new Client(args[0], port); + await client.RunAsync(); +} + +async Task StartServer(string[] args) +{ + if (!int.TryParse(args[0], out var port)) + { + throw new ArgumentException(); + } + + using var server = new Server(port); + await server.RunAsync(); +} \ No newline at end of file diff --git a/WebChat/WebChat/Server.cs b/WebChat/WebChat/Server.cs new file mode 100644 index 0000000..1c0611c --- /dev/null +++ b/WebChat/WebChat/Server.cs @@ -0,0 +1,68 @@ +namespace WebChat; + +using System.Net; +using System.Net.Sockets; + +/// +/// Chat server. +/// +public class Server : IDisposable +{ + private readonly TcpListener _listener; + + private readonly CancellationTokenSource _cts = new (); + + /// + /// Initializes a new instance of the class. + /// + public Server(int port) + { + _listener = new TcpListener(IPAddress.Any, port); + } + + /// + /// Gets a value indicating whether the server is disposed. + /// + public bool IsDisposed { get; private set; } + + private void Stop() => _cts.Cancel(); + + /// + /// Releases all resources used by the current instance of the class. + /// + public void Dispose() + { + if (IsDisposed) + { + return; + } + + if (!_cts.IsCancellationRequested) + { + Stop(); + } + + _cts.Dispose(); + IsDisposed = true; + } + + /// + /// Runs server. + /// + public async Task RunAsync() + { + _listener.Start(); + + try + { + var token = _cts.Token; + using var socket = await _listener.AcceptSocketAsync(token); + await using var stream = new NetworkStream(socket); + await Processing.ProcessQuery(stream); + } + finally + { + _listener.Stop(); + } + } +} diff --git a/WebChat/WebChat/WebChat.csproj b/WebChat/WebChat/WebChat.csproj new file mode 100644 index 0000000..b9de063 --- /dev/null +++ b/WebChat/WebChat/WebChat.csproj @@ -0,0 +1,10 @@ + + + + Exe + net6.0 + enable + enable + + +