async Task <Result> ClientSingleConnectionAsync(Direction dir, AsyncManualResetEvent fireMeWhenReady, CancellationToken cancel) { Result ret = new Result(); using (NetPalTcpProtocolStub tcp = new NetPalTcpProtocolStub(cancel: cancel)) { await tcp.ConnectAsync(ServerIP, ServerPort, cancel, ConnectTimeout); using (ConnSock sock = new ConnSock(tcp)) { NetAppStub app = sock.GetNetAppProtocolStub(); AttachHandle attachHandle = app.AttachHandle; PipeStream st = app.GetStream(); if (dir == Direction.Recv) { app.AttachHandle.SetStreamReceiveTimeout(RecvTimeout); } try { var hello = await st.ReceiveAllAsync(16); if (hello.Span.ToArray()._GetString_Ascii().StartsWith("TrafficServer\r\n") == false) { throw new ApplicationException("Target server is not a Traffic Server."); } //throw new ApplicationException("aaaa" + dir.ToString()); fireMeWhenReady.Set(); cancel.ThrowIfCancellationRequested(); await TaskUtil.WaitObjectsAsync( manualEvents : ClientStartEvent._SingleArray(), cancels : cancel._SingleArray() ); 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 TaskUtil.WaitObjectsAsync( tasks : st.FastReceiveAsync(totalRecvSize : totalRecvSize)._SingleArray(), 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 TaskUtil.WaitObjectsAsync( manualEvents: sock.Pipe.OnDisconnectedEvent._SingleArray(), timeout: 200); } }); await WhenAll.Await(false, recvResult, sendSurprise); await recvResult; } st.Disconnect(); return(ret); } catch (Exception ex) { ExceptionQueue !.Add(ex); throw; } } } }
public WhenAllCollectionObserver(WhenAll parent, int index) { this.parent = parent; this.index = index; }
public async Task <Result?> RunClientAsync() { CurrentCount.Increment(); try { if (Once.IsFirstCall() == false) { throw new ApplicationException("You cannot reuse the object."); } Con.WriteLine("Client mode start"); ExceptionQueue = new ExceptionQueue(); SessionId = Util.RandUInt64(); List <Task <Result> > tasks = new List <Task <Result> >(); List <AsyncManualResetEvent> readyEvents = new List <AsyncManualResetEvent>(); using (CancelWatcher cancelWatcher = new CancelWatcher(this.Cancel)) { for (int i = 0; i < NumConnection; i++) { Direction dir; if (Mode == SpeedTestModeFlag.Download) { dir = Direction.Recv; } else if (Mode == SpeedTestModeFlag.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 TaskUtil.WaitObjectsAsync( tasks : tasks.Append(whenAllReady.WaitMe).ToArray(), cancels : cancelWatcher.CancelToken._SingleArray(), manualEvents : ExceptionQueue.WhenExceptionAdded._SingleArray()); } Cancel.ThrowIfCancellationRequested(); ExceptionQueue.ThrowFirstExceptionIfExists(); ExceptionQueue.WhenExceptionAdded.CallbackList.AddSoftCallback(x => { cancelWatcher.Cancel(); }); using (new DelayAction(TimeSpan * 3 + 180 * 1000, x => { cancelWatcher.Cancel(); }, doNotBlockOnDispose: true)) { ClientStartEvent.Set(true); using (var whenAllCompleted = new WhenAll(tasks)) { await TaskUtil.WaitObjectsAsync( tasks : whenAllCompleted.WaitMe._SingleArray(), cancels : cancelWatcher.CancelToken._SingleArray() ); await whenAllCompleted.WaitMe; } } Result ret = new Result(); ret.Span = TimeSpan; foreach (var r in tasks.Select(x => x._GetResult())) { 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(); } return(null); } finally { CurrentCount.Decrement(); } }