using System; using System.Threading.Tasks; using Vinno.IUS.Common.IO; using Vinno.IUS.Common.Network.Tcp; using Vinno.IUS.Common.Network.Tcp.Extensions; using Vinno.IUS.Common.Network.IO; namespace Vinno.IUS.Common.Network.Channels { public class ClientChannel:Channel { private readonly ITcp _tcp; private int _readTimeoutTranscationLevel; private int _writeTimeoutTranscationLevel; /// /// Gets the total data transfered include send and receive. /// public long DataTransfered { get; private set; } public ClientChannel(int channelId, ITcp tcp):base(channelId) { _tcp = tcp; Remote = _tcp.Remote; Local = _tcp.Local; } /// /// Read and validate the header from remote. /// /// Wait forever if the value is 0 protected override void ReadHeader(int timeout = 0) { //Notice that when network is shutdown, it may not know it's shutdown, //But when read data from socket, it will read 0 byte, that's can used for //Check if network is shutdown. using (new ReadTimeoutTranscation(this, timeout)) { //ReadBinary may throw exception when network is shutdown, and readed data length is zero. var headerData = _tcp.ReadBinary(8); ValidateHeader(headerData); DataTransfered += 8; } } /// /// Read and validate the header from remote by async way. /// /// Wait forever if the value is 0 protected override async Task ReadHeaderAsync(int timeout = 0) { //Notice that when network is shutdown, it may not know it's shutdown, //But when read data from socket, it will read 0 byte, that's can used for //Check if network is shutdown. using (new ReadTimeoutTranscation(this, timeout)) { //ReadBinary may throw exception when network is shutdown, and read data length is zero. var headerData = await _tcp.ReadBinaryAsync(8).ConfigureAwait(false); ValidateHeader(headerData); DataTransfered += 8; } } /// /// Write the header before write buffer. /// /// Wait forever if the value is 0 protected override void WriteHeader(int timeout = 0) { using (new WriteTimeoutTranscation(this, timeout)) { var headerData = GetHeaderData(); //Write header _tcp.WriteBinary(headerData); DataTransfered += 8; } } /// /// Write the header before write buffer by async way. /// /// Wait forever if the value is 0 protected override async Task WriteHeaderAsync(int timeout = 0) { using (new WriteTimeoutTranscation(this, timeout)) { var headerData = GetHeaderData(); //Write header await _tcp.WriteBinaryAsync(headerData).ConfigureAwait(false); DataTransfered += 8; } } /// /// Read buffer from remote side. /// /// Wait forever if the value is 0 /// The buffer readed from network. protected IBuffer ReadBuffer(int timeout = 0) { using (new ReadTimeoutTranscation(this, timeout)) { var reader = new BufferReader(_tcp.ReadStream); var buffer = reader.ReadBuffer(); DataTransfered += buffer.Size; return buffer; } } /// /// Read buffer from remote side by async way. /// /// Wait forever if the value is 0 /// The buffer readed from network. protected async Task ReadBufferAsync(int timeout = 0) { using (new ReadTimeoutTranscation(this, timeout)) { var reader = new AsyncBufferReader(_tcp.ReadStream); var buffer = await reader.ReadBufferAsync().ConfigureAwait(false); DataTransfered += buffer.Size; return buffer; } } /// /// Write buffer to remote side. /// /// The buffer to be writen /// Wait forever if the value is 0 protected void WriteBuffer(IBuffer buffer, int timeout = 0) { using (new WriteTimeoutTranscation(this, timeout)) { var writer = new BufferWriter(_tcp.WriteStream); writer.WriteBuffer(buffer); DataTransfered += buffer.Size; } } /// /// Write buffer to remote side by async way. /// /// The buffer to be writen /// Wait forever if the value is 0 protected async Task WriteBufferAsync(IBuffer buffer, int timeout = 0) { using (new WriteTimeoutTranscation(this, timeout)) { var writer = new AsyncBufferWriter(_tcp.WriteStream); await writer.WriteBufferAsync(buffer).ConfigureAwait(false); DataTransfered += buffer.Size; } } protected override void OnClosed() { _tcp.Disconnect(); base.OnClosed(); } public override string ToString() { return $"{Remote}<->{Local}"; } private class ReadTimeoutTranscation : IDisposable { private readonly ClientChannel _channel; public ReadTimeoutTranscation(ClientChannel channel, int timeout) { _channel = channel; if (_channel._readTimeoutTranscationLevel == 0) { try { _channel._tcp.ReadTimeout = timeout; } catch { //DO Nothing. } } _channel._readTimeoutTranscationLevel++; } public void Dispose() { _channel._readTimeoutTranscationLevel--; if (_channel._readTimeoutTranscationLevel == 0) { try { _channel._tcp.ReadTimeout = 0; } catch { //DO Nothing. } } } } private class WriteTimeoutTranscation : IDisposable { private readonly ClientChannel _channel; public WriteTimeoutTranscation(ClientChannel channel, int timeout) { _channel = channel; if (_channel._writeTimeoutTranscationLevel == 0) { try { _channel._tcp.SendTimeout = timeout; } catch { //DO Nothing. } } _channel._writeTimeoutTranscationLevel++; } public void Dispose() { _channel._writeTimeoutTranscationLevel--; if (_channel._writeTimeoutTranscationLevel == 0) { try { _channel._tcp.SendTimeout = 0; } catch { //DO Nothing. } } } } } }