namespace Tcplib.Server { using System; using System.Net.Sockets; using System.Threading.Tasks; /// /// Вспомогательный класс содержащий в себе информацию о текущей сессии /// public class Session { private const int defaultBufferSize = 1024; private byte[] _readBuffer; private byte[] _writeBuffer; private readonly TcpServer _owner; private TcpClient _client; public Guid Guid { get; } public Session(TcpServer owner, TcpClient client, Guid guid, int readBudderSize = 1024, int writeBufferSize = 1024) { _owner = owner; _client = client; Guid = guid; if (readBudderSize <= 0) readBudderSize = defaultBufferSize; if (writeBufferSize <= 0) writeBufferSize = defaultBufferSize; _readBuffer = new byte[readBudderSize]; _writeBuffer = new byte[writeBufferSize]; } /// /// Метод получения датаграммы от клиента /// /// /// /// public async Task?> TryReceiveData(int retryCount = 5, int retryDelayMS = 1000) { int readed = 0; try { var ns = _client.GetStream(); do { readed += await ns.ReadAsync(_readBuffer.AsMemory().Slice(readed)); if (_client.Client.Available == 0 || readed >= _readBuffer.Length)//мы прочитали все данные или в буффере уже нет места break; } while (ns.DataAvailable || retryCount > 0); } catch (SocketException ex) { Console.WriteLine("[WARN] SocketException in TryReceiveData"); Console.WriteLine(ex.ToString()); } catch (ObjectDisposedException ex) { Console.WriteLine("[WARN] ObjectDisposedException in TryReceiveData"); Console.WriteLine(ex.ToString()); } catch (Exception ex) { Console.WriteLine("[WARN] UndefinedException in TryReceiveData"); Console.WriteLine(ex.ToString()); } return _readBuffer[0..readed]; } /// /// ИИетод отправки датаграммы клиенту /// /// /// /// /// public async Task TrySendData(ReadOnlyMemory datagramm, int retryCount = 5, int retryDelayMS = 1000) { try { var ns = _client.GetStream(); do { try { await ns.WriteAsync(datagramm); retryCount = 0; } catch (SocketException ex) { Console.WriteLine("[WARN] SocketException in TrySendData"); Console.WriteLine(ex.ToString()); } catch (ObjectDisposedException ex) { Console.WriteLine("[WARN] ObjectDisposedException in TrySendData"); Console.WriteLine(ex.ToString()); } catch (Exception ex) { Console.WriteLine("[WARN] UndefinedException in TrySendData"); Console.WriteLine(ex.ToString()); } retryCount--; await Task.Delay(retryCount); } while (retryCount > 0); } catch (SocketException ex) { Console.WriteLine("[WARN] SocketException in TrySendData"); Console.WriteLine(ex.ToString()); } catch (ObjectDisposedException ex) { Console.WriteLine("[WARN] ObjectDisposedException in TrySendData"); Console.WriteLine(ex.ToString()); } catch (Exception ex) { Console.WriteLine("[WARN] UndefinedException in TrySendData"); Console.WriteLine(ex.ToString()); } } public void StopSession() { try { _client.Close(); _client.Dispose(); } catch (SocketException ex) { Console.WriteLine("[WARN] SocketException in StopSession"); Console.WriteLine(ex.ToString()); } catch (ObjectDisposedException ex) { Console.WriteLine("[WARN] ObjectDisposedException in StopSession"); Console.WriteLine(ex.ToString()); } catch (Exception ex) { Console.WriteLine("[WARN] UndefinedException in StopSession"); Console.WriteLine(ex.ToString()); } } } } namespace Tcplib.Server { using System.Net.Sockets; using System.Threading; using System.Collections.Concurrent; using System; using System.Threading.Tasks; public class TcpServer { #region Events public event ServerStartedHandler ServerStarted; public event ServerStopedHandler ServerStoped; public event ClientConnectedHandler ClientAccepted; public event ClientDisconnectedHandler ClientDisconnected; #endregion Events #region ServerSettings private readonly ServerConfig _config; #endregion ServerSettings #region ServerFields private readonly TcpListener _listener; private readonly CancellationTokenSource _cancellationTokenSource; private readonly int _maxConnections; private readonly ConcurrentDictionary _sessions = new ConcurrentDictionary(); #endregion #region ServerProperties public bool IsStarted { get; private set; } #endregion ServerProperties public TcpServer(ServerConfig config) { _config = config; _listener = new TcpListener(_config.ListeningEndPoint); _maxConnections = _config.MaxConnections; _cancellationTokenSource = new CancellationTokenSource(); } #region Server public methods public async void Start() { if(IsStarted) return; try{ var token = _cancellationTokenSource.Token; _listener.Start(); IsStarted = true; await Task.Run(() => AcceptCients(token)); } catch(Exception ex) { Console.WriteLine("[WARN] UndefinedException in Start"); Console.WriteLine(ex.ToString()); } } public void Stop() { if(!IsStarted) return; try { _listener.Stop(); foreach(var c in _sessions.Values) { try{ c.StopSession(); } catch(Exception ex) { Console.WriteLine("[WARN] UndefinedException in Start"); Console.WriteLine(ex.ToString()); } } _sessions.Clear(); } catch (SocketException ex) { Console.WriteLine("[WARN] SocketException in Stop"); Console.WriteLine(ex.ToString()); } catch (ObjectDisposedException ex) { Console.WriteLine("[WARN] ObjectDisposedException in Stop"); Console.WriteLine(ex.ToString()); } catch (Exception ex) { Console.WriteLine("[WARN] UndefinedException in Stop"); Console.WriteLine(ex.ToString()); } } #endregion #region Server private methods private async Task AcceptCients(CancellationToken cancellationToken){ try{ while (IsStarted && !cancellationToken.IsCancellationRequested) { var acceptedClient = await _listener.AcceptTcpClientAsync(); Guid clientGuid = Guid.NewGuid(); var session = new Session(this, acceptedClient,clientGuid); if(!_sessions.TryAdd(clientGuid, session)) { session.StopSession(); continue; } ProcessSession(session); } } catch (SocketException ex) { Console.WriteLine("[WARN] SocketException in Stop"); Console.WriteLine(ex.ToString()); } catch (ObjectDisposedException ex) { Console.WriteLine("[WARN] ObjectDisposedException in Stop"); Console.WriteLine(ex.ToString()); } catch (Exception ex) { Console.WriteLine("[WARN] UndefinedException in Stop"); Console.WriteLine(ex.ToString()); } } public Action ProcessSessionHandler; private async void ProcessSession(Session session) { if(ProcessSessionHandler==null) return; await Task.Run(()=> ProcessSessionHandler(session)); try { session.StopSession(); } catch(Exception ex) { Console.WriteLine("[WARN] UndefinedException in ProcessSession"); } if(!_sessions.TryRemove(session.Guid, out var s)) { Console.WriteLine($"Cant remove session {session.Guid}"); } } #endregion Server private methods } }