internal async void RegisterAckTask(AckTask ackTask) { lock (Locker) { if (AckTaskList.TryAdd(ackTask.Ack.Value, ackTask)) { } else { // 理论上是找不到的 } } await ackTask.Task.Task; lock (Locker) { if (AckTaskList.Remove(ackTask.Ack.Value, out var removedTask)) { Debug.Assert(ReferenceEquals(removedTask, ackTask)); } else { Debug.Assert(false, "收到的一定存在"); } } }
internal async Task <bool> DoWillReceivedAck(Func <Ack, Task> task, string peerName, TimeSpan timeout, uint maxRetryCount) { for (uint i = 0; i < maxRetryCount; i++) { var ack = GetAck(); var taskCompletionSource = new TaskCompletionSource <bool>(); var ackTask = new AckTask(peerName, ack, taskCompletionSource); RegisterAckTask(ackTask); // 先注册,然后执行任务,解决任务速度太快,收到消息然后再注册 await task(ack); await Task.WhenAny(taskCompletionSource.Task, Task.Delay(timeout)); taskCompletionSource.TrySetResult(false); if (await taskCompletionSource.Task) { // 执行完成 return(true); } } // 执行失败 return(false); }
/// <summary> /// 廣播訊息 /// </summary> /// <param name="message"></param> public void Broadcasting(byte[] pkg, ushort dataType) { var newTask = new AckTask() { DataBytes = pkg, DataType = dataType, StartTime = DateTime.Now }; fCastingMessage.Enqueue(newTask); }
public void RegisterAckTask() { "将消息注册,此时设置收到回复,注册的消息可以完成".Test(() => { // 注册的消息可以完成 var clientName = "lindexi"; Ack ack = 2; var taskCompletionSource = new TaskCompletionSource <bool>(); var ackTask = new AckTask(clientName, ack, taskCompletionSource); AckManager.RegisterAckTask(ackTask); AckManager.OnAckReceived(this, new AckArgs(clientName, ack)); //Debug.Assert(taskCompletionSource.Task.IsCompleted); Assert.AreEqual(true, taskCompletionSource.Task.IsCompleted); }); }
public void RegisterAckTask() { "重复注册相同编号的消息,提示错误".Test(() => { var clientName = "lindexi"; Ack ack = 20; var taskCompletionSource = new TaskCompletionSource <bool>(); var ackTask = new AckTask(clientName, ack, taskCompletionSource, "调试"); AckManager.RegisterAckTask(ackTask); Assert.ThrowsException <ArgumentException>(() => { AckManager.RegisterAckTask(ackTask); }); }); "将消息注册,如果没有收到回复,那么注册的任务依然没有完成".Test(() => { // 注册的消息可以完成 var clientName = "lindexi"; Ack ack = 2; var taskCompletionSource = new TaskCompletionSource <bool>(); var ackTask = new AckTask(clientName, ack, taskCompletionSource, "调试"); AckManager.RegisterAckTask(ackTask); Assert.AreEqual(false, taskCompletionSource.Task.IsCompleted); }); "将消息注册,此时设置收到回复,注册的消息可以完成".Test(() => { // 注册的消息可以完成 var clientName = "lindexi"; Ack ack = 2; var taskCompletionSource = new TaskCompletionSource <bool>(); var ackTask = new AckTask(clientName, ack, taskCompletionSource, "调试"); AckManager.RegisterAckTask(ackTask); AckManager.OnAckReceived(this, new AckArgs(clientName, ack)); //Debug.Assert(taskCompletionSource.Task.IsCompleted); Assert.AreEqual(true, taskCompletionSource.Task.IsCompleted); }); }
/// <summary> /// 送出通知工作 /// </summary> /// <param name="message">封包資料</param> /// <param name="outputMessages">回傳輸出訊息</param> private void SendBroadcasting(AckTask message, out List <string> outputMessages) { outputMessages = new List <string>(); Stopwatch watchTime = new Stopwatch(); watchTime.Start(); var usedTicks = new List <string>(); //打出通知 SendStatistics statistics = new SendStatistics(); Stopwatch taskWatch = new Stopwatch(); Stopwatch writeWatch = new Stopwatch(); var needRemoveClients = new List <ProxyClient>(); foreach (var client in fClientPool) { taskWatch.Restart(); string tickMessage; bool isWriteSuccess = client.SendBroadcastingToClient(message, writeWatch, statistics, outputMessages, out tickMessage); if (!isWriteSuccess) { needRemoveClients.Add(client); } taskWatch.Stop(); if (taskWatch.ElapsedMilliseconds > REASONABLE_TIME_GRID_BY_TASK) { usedTicks.Add(string.Format("{0}[{1}]", taskWatch.ElapsedMilliseconds, tickMessage ?? "Exception")); } } //取得工作建立到完成的時間間格 var taskTimeSpan = DateTime.Now - message.StartTime; if (message.DataType != 0) { fSendCount++; var taskTime = taskTimeSpan.TotalMilliseconds; if (taskTime > fMaxSendMs) { fMaxSendMs = taskTime; fMaxSendMsTimeStamp = DateTime.Now; } fTotalSendMs += taskTime; fLastSendMs = taskTime; } //如果單次轉發超過300ms就應該注意 watchTime.Stop(); if (watchTime.ElapsedMilliseconds > REASONABLE_TIME_GRID) { outputMessages.Add(string.Format("SendBroadcasting Milliseconds : {0}", watchTime.ElapsedMilliseconds)); outputMessages.Add(string.Format("TotalCount : {0} SuccessCount : {1} ExceptionCount : {2}", statistics.TotalSendCount, statistics.SuccessSendCount, statistics.ExceptionSendCount)); outputMessages.Add(string.Format("UsedTicksList : {0}", string.Join(" , ", usedTicks))); } //移除無效連線 if (needRemoveClients.Count > 0) { removeConnections(needRemoveClients); } }
/// <summary> /// 發送封包到客端 /// </summary> /// <param name="message">轉發封包資訊</param> /// <param name="writeWatch">封包送出時間監視器</param> /// <param name="statistics">發送統計資訊</param> /// <param name="outputMessages">輸出訊息清單</param> /// <param name="tickMessage">發送的時間訊息</param> /// <returns>是否發送成功</returns> public bool SendBroadcastingToClient(AckTask message, Stopwatch writeWatch, SendStatistics statistics, List <string> outputMessages, out string tickMessage) { bool isSuccess = false; tickMessage = null; try { if (this.fClientSocket.Connected) { //ACK if (statistics != null) { statistics.TotalSendCount++; } writeWatch.Restart(); //發送資料 var stream = this.fClientStream; this.fClientStream.BeginWrite(message.DataBytes, 0, message.DataBytes.Length, AsyncSendCallback, statistics); isSuccess = true; this.AsyncSendCount++; writeWatch.Stop(); //處理讀取資料(下端心跳) if (this.fClientStream.DataAvailable) { //client端 只讀心跳包 byte[] buffer = new byte[TCP_BUFFER_SIZE]; this.fClientStream.BeginRead(buffer, 0, buffer.Length, AsyncReceiveCallback, buffer); this.AsyncReadCount++; } tickMessage = string.Format("W:{0}", writeWatch.ElapsedMilliseconds); } } catch (IOException ex) { IsErrorClient = true; SocketException se = ex.InnerException as SocketException; int errorCode = se == null ? -1 : se.ErrorCode; outputMessages.Add(string.Format("TcpEx:Send SocketErr={0} {1}", errorCode, this.Address)); isSuccess = false; if (statistics != null) { statistics.ExceptionSendCount++; } } catch (Exception ex) { IsErrorClient = true; outputMessages.Add(string.Format("TcpEx:Send Err={0} {1}", ex.Message, this.Address)); isSuccess = false; if (statistics != null) { statistics.ExceptionSendCount++; } } return(isSuccess); }