async Task <Result> ClientSingleConnectionAsync(Direction dir, AsyncManualResetEvent fireMeWhenReady, CancellationToken cancel) { Result ret = new Result(); AsyncCleanuperLady lady = new AsyncCleanuperLady(); try { var tcp = new FastPalTcpProtocolStub(lady, cancel: cancel); var sock = await tcp.ConnectAsync(ServerIP, ServerPort, cancel, ConnectTimeout); var app = sock.GetFastAppProtocolStub(); var attachHandle = app.AttachHandle; var st = app.GetStream(); if (dir == Direction.Recv) { app.AttachHandle.SetStreamReceiveTimeout(RecvTimeout); } try { var hello = await st.ReceiveAllAsync(16); Dbg.Where(); if (Encoding.ASCII.GetString(hello.Span).StartsWith("TrafficServer\r\n") == false) { throw new ApplicationException("Target server is not a Traffic Server."); } Dbg.Where(); //throw new ApplicationException("aaaa" + dir.ToString()); fireMeWhenReady.Set(); cancel.ThrowIfCancellationRequested(); await WebSocketHelper.WaitObjectsAsync( manualEvents : ClientStartEvent.ToSingleArray(), cancels : cancel.ToSingleArray() ); long tickStart = FastTick64.Now; long tickEnd = tickStart + this.TimeSpan; var sendData = new MemoryBuffer <byte>(); sendData.WriteBool8(dir == Direction.Recv); sendData.WriteUInt64(SessionId); sendData.WriteSInt64(TimeSpan); await st.SendAsync(sendData); if (dir == Direction.Recv) { RefInt totalRecvSize = new RefInt(); while (true) { long now = FastTick64.Now; if (now >= tickEnd) { break; } await WebSocketHelper.WaitObjectsAsync( tasks : st.FastReceiveAsync(totalRecvSize : totalRecvSize).ToSingleArray(), timeout : (int)(tickEnd - now), exceptions : ExceptionWhen.TaskException | ExceptionWhen.CancelException); ret.NumBytesDownload += totalRecvSize; } } else { attachHandle.SetStreamReceiveTimeout(Timeout.Infinite); while (true) { long now = FastTick64.Now; if (now >= tickEnd) { break; } /*await WebSocketHelper.WaitObjectsAsync( * tasks: st.FastSendAsync(SendData, flush: true).ToSingleArray(), * timeout: (int)(tick_end - now), * exceptions: ExceptionWhen.TaskException | ExceptionWhen.CancelException);*/ await st.FastSendAsync(SendData, flush : true); } Task recvResult = Task.Run(async() => { var recvMemory = await st.ReceiveAllAsync(8); MemoryBuffer <byte> recvMemoryBuf = recvMemory; ret.NumBytesUpload = recvMemoryBuf.ReadSInt64(); st.Disconnect(); }); Task sendSurprise = Task.Run(async() => { byte[] surprise = new byte[260]; surprise.AsSpan().Fill((byte)'!'); while (true) { await st.SendAsync(surprise); await WebSocketHelper.WaitObjectsAsync( manualEvents: sock.Pipe.OnDisconnectedEvent.ToSingleArray(), timeout: 200); } }); await WhenAll.Await(false, recvResult, sendSurprise); await recvResult; } st.Disconnect(); Dbg.Where(); return(ret); } catch (Exception ex) { Dbg.Where(ex.Message); ExceptionQueue.Add(ex); throw; } } finally { await lady; } }
public async Task <Result> RunClientAsync() { if (IsServerMode) { throw new ApplicationException("Server mode"); } if (Once.IsFirstCall() == false) { throw new ApplicationException("You cannot reuse the object."); } WriteLine("Client mode start"); ExceptionQueue = new ExceptionQueue(); SessionId = WebSocketHelper.RandUInt64(); List <Task <Result> > tasks = new List <Task <Result> >(); List <AsyncManualResetEvent> readyEvents = new List <AsyncManualResetEvent>(); AsyncCleanuperLady lady = new AsyncCleanuperLady(); try { CancelWatcher cancelWatcher = new CancelWatcher(lady, this.Cancel); for (int i = 0; i < NumConnection; i++) { Direction dir; if (Mode == ModeFlag.Download) { dir = Direction.Recv; } else if (Mode == ModeFlag.Upload) { dir = Direction.Send; } else { dir = ((i % 2) == 0) ? Direction.Recv : Direction.Send; } AsyncManualResetEvent readyEvent = new AsyncManualResetEvent(); var t = ClientSingleConnectionAsync(dir, readyEvent, cancelWatcher.CancelToken); ExceptionQueue.RegisterWatchedTask(t); tasks.Add(t); readyEvents.Add(readyEvent); } try { using (var whenAllReady = new WhenAll(readyEvents.Select(x => x.WaitAsync()))) { await WebSocketHelper.WaitObjectsAsync( tasks : tasks.Append(whenAllReady.WaitMe).ToArray(), cancels : cancelWatcher.CancelToken.ToSingleArray(), manualEvents : ExceptionQueue.WhenExceptionAdded.ToSingleArray()); } Cancel.ThrowIfCancellationRequested(); ExceptionQueue.ThrowFirstExceptionIfExists(); ExceptionQueue.WhenExceptionAdded.CallbackList.AddSoftCallback(x => { cancelWatcher.Cancel(); }); using (new DelayAction(lady, TimeSpan * 3 + 180 * 1000, x => { cancelWatcher.Cancel(); })) { ClientStartEvent.Set(true); using (var whenAllCompleted = new WhenAll(tasks)) { await WebSocketHelper.WaitObjectsAsync( tasks : whenAllCompleted.WaitMe.ToSingleArray(), cancels : cancelWatcher.CancelToken.ToSingleArray() ); await whenAllCompleted.WaitMe; } } Result ret = new Result(); ret.Span = TimeSpan; foreach (var r in tasks.Select(x => x.Result)) { ret.NumBytesDownload += r.NumBytesDownload; ret.NumBytesUpload += r.NumBytesUpload; } ret.NumBytesTotal = ret.NumBytesUpload + ret.NumBytesDownload; ret.BpsUpload = (long)((double)ret.NumBytesUpload * 1000.0 * 8.0 / (double)ret.Span * 1514.0 / 1460.0); ret.BpsDownload = (long)((double)ret.NumBytesDownload * 1000.0 * 8.0 / (double)ret.Span * 1514.0 / 1460.0); ret.BpsTotal = ret.BpsUpload + ret.BpsDownload; return(ret); } catch (Exception ex) { await Task.Yield(); ExceptionQueue.Add(ex); } finally { cancelWatcher.Cancel(); try { await Task.WhenAll(tasks); } catch { } } ExceptionQueue.ThrowFirstExceptionIfExists(); } finally { await lady; } Dbg.Where(); return(null); }