async Task SendLoopAsync() { try { CancellationToken cancel = this.GrandCancel; LocalTimer timer = new LocalTimer(); long nextPingTick = timer.AddTimeout(0); while (true) { await LowerStream.WaitReadyToSendAsync(cancel, Timeout.Infinite); await UpperStream.WaitReadyToReceiveAsync(cancel, timer.GetNextInterval(), noTimeoutException : true, cancelEvent : this.SendPongEvent); MemoryBuffer <byte> sendBuffer = new MemoryBuffer <byte>(); IReadOnlyList <ReadOnlyMemory <byte> > userDataList = UpperStream.FastReceiveNonBlock(out int totalRecvSize, maxSize: Options.MaxBufferSize); if (totalRecvSize >= 1) { // Send data if (Options.RespectMessageDelimiter == false) { userDataList = Util.DefragmentMemoryArrays(userDataList, Options.SendSingleFragmentSize); } foreach (ReadOnlyMemory <byte> userData in userDataList) { if (userData.Length >= 1) { BuildAndAppendFrame(sendBuffer, true, WebSocketOpcode.Bin, userData); } } } if (timer.Now >= nextPingTick) { // Send ping nextPingTick = timer.AddTimeout(Util.GenRandInterval(Options.SendPingInterval)); BuildAndAppendFrame(sendBuffer, true, WebSocketOpcode.Ping, "[WebSocketPing]"._GetBytes_Ascii()); } lock (this.PongQueueLock) { // Send pong while (true) { if (this.PongQueue.TryDequeue(out ReadOnlyMemory <byte> data) == false) { break; } BuildAndAppendFrame(sendBuffer, true, WebSocketOpcode.Pong, data); } } if (sendBuffer.Length >= 1) { LowerStream.FastSendNonBlock(sendBuffer.Memory); } } } catch (Exception ex) { this.UpperStream.Disconnect(); this.Cancel(ex); } }
async Task SendLoopAsync(int keepaliveInterval) { try { CancellationToken cancel = this.GrandCancel; LocalTimer timer = new LocalTimer(); long nextPingTick = timer.AddTimeout(0); bool initialFourZeroSent = false; bool localFlag_C2S_SwitchToWebSocket_Requested = false; while (true) { MemoryBuffer <byte> sendBuffer = new MemoryBuffer <byte>(); if (initialFourZeroSent == false) { // 最初の 0x00000000 (4 バイト) を送信 initialFourZeroSent = true; sendBuffer.WriteSInt32(4); sendBuffer.WriteSInt32(0x00000000); } // 上位ストリームからのデータを送信 IReadOnlyList <ReadOnlyMemory <byte> > userDataList = UpperStream.FastReceiveNonBlock(out int totalSendSize, maxSize: Consts.WideTunnelConsts.MaxBlockSize); if (totalSendSize >= 1) { // Send data foreach (var mem in userDataList) { //$"Send: {mem.Length}"._Debug(); //$"SendData: {mem._GetHexString()}"._Debug(); sendBuffer.WriteSInt32(mem.Length); sendBuffer.Write(mem); } } if (timer.Now >= nextPingTick) { // Send ping sendBuffer.WriteSInt32(0); nextPingTick = timer.AddTimeout(Util.GenRandInterval(keepaliveInterval)); } if (localFlag_C2S_SwitchToWebSocket_Requested == false && this.C2S_SwitchToWebSocket_Requested) { // Web socket switch request invoked (only once) $"Web socket switch request invoked"._Debug(); localFlag_C2S_SwitchToWebSocket_Requested = true; sendBuffer.WriteSInt32(Consts.WideTunnelConsts.SpecialOpCode_C2S_SwitchToWebSocket_Request_Guacd); } if (sendBuffer.IsThisEmpty() == false) { //$"RawSendData: {sendBuffer.Span._GetHexString()}"._Debug(); LowerStream.FastSendNonBlock(sendBuffer); } await LowerStream.WaitReadyToSendAsync(cancel, Timeout.Infinite); await UpperStream.WaitReadyToReceiveAsync(cancel, timer.GetNextInterval(), noTimeoutException : true, cancelEvent : C2S_SpecialOp_Event); } } catch (Exception ex) { // ex._Debug(); this.UpperStream.Disconnect(); await this.CleanupAsync(ex); } }