下面貼上我目前的實作方法:
public async Task<StartDownloadResponseMsg> StartDownloadRequestAsync(StartDownloadMsg msg, int requestCount, TimeSpan interval)
{
var data = MessageConverter.Serialize(msg);
var response = await Request(msg.Header.MessageType, data, requestCount, interval);
return MessageConverter.Deserialize<StartDownloadResponseMsg>(response);
}
請求實作:
private async Task<byte[]> Request(MessageType type, byte[] msg, int requestCount, TimeSpan interval)
{
ValidRequest(type);
_cts = new CancellationTokenSource();
try
{
for (int count = 0; count < requestCount; count++)
{
Send(msg);
await Task.Delay(interval, _cts.Token);
}
}
catch (OperationCanceledException)
{
TaskCompletionSource<byte[]> task = new TaskCompletionSource<byte[]>();
task.SetResult(_response);
return await task.Task;
}
finally
{
_isRequesting = false;
_response = null;
}
throw new RequestTimeoutException();
}
接識訓呼:
private void ReceiveCallback(IAsyncResult async)
{
Socket socket = async.AsyncState as Socket;
int length = socket.EndReceive(async);
_buffer.Write(_received, 0, length);
_buffer.Seek(-length, SeekOrigin.End);
while (_buffer.Length - _buffer.Position >= CanFrameLength)
{
byte[] package = new byte[CanFrameLength];
_buffer.Read(package, 0, CanFrameLength);
var type = (MessageType)package[TypeOffset];
switch (type)
{
case MessageType.StartDownloadResponse:
case MessageType.DemandSectionResponseTwo:
case MessageType.CombinePackageResponse:
case MessageType.CombinePackageCompletedResponse:
case MessageType.ProgramCheckoutResponse:
case MessageType.ResetImmeiateResponse:
if (_isRequesting && type == _waitResponseType) // 正在請求并且報文型別為等待回應的型別
{
_response = package;
_cts.Cancel(); // 直接取消請求任務
}
break;
case MessageType.HeartbeatResponse:
_lastHeartbeat++;
break;
default:
break;
}
}
socket.BeginReceive(_received, 0, _received.Length, SocketFlags.None, ReceiveCallback, socket);
}
另外我能想到的方法就是每次請求開啟一個定時器定時發送請求,接識訓呼接收到指定回應后停止計時器并通過事件通知請求者,計時器到達指定次數還沒有停止就拋出超時例外,這個處理方式不能直接在請求函式里面回傳應答,使用起來比較麻煩。
還有就是使用WaitHandle來同步,請求函式里面回圈發送改為:
for (int count = 0; count < requestCount; count++)
{
Send(msg);
if (resetEvent.WaitOne(interval))
{
return _response;
}
}
接收到指定回應后呼叫resetEvent.Set(),這種方式回阻塞請求執行緒
不知道大家有沒有更加優雅的
uj5u.com熱心網友回復:
我也在寫類似的東西,我是這樣處理的
class FunctionRquestData
{
private Stopwatch sw = new Stopwatch();
public class packagedata
{
FunctionRquestData f;
public Dictionary<int, byte[]> data = new Dictionary<int, byte[]>();
public void addreceivedata(int n,byte[] d)
{
if (!data.ContainsKey(n))
{
data.Add(n, d);
f.finished = false;
f.checkdone();
f.sw.Restart();
}
}
public void addsenddata(int n, byte[] d)
{
//if (!data.ContainsKey(n))
{
data.Add(n, d);
udp.Send(d, d.Length, f.ip) ;
}
}
public int count()
{
return data.Count;
}
public void clear()
{
data.Clear();
}
public packagedata(FunctionRquestData F)
{
f = F;
}
}
void checkdone()
{
//判斷是否完整
}
void checktimeout()
{
System.Timers.Timer dt = new System.Timers.Timer() { Enabled = true, Interval = 100};
dt.Elapsed += delegate
{
if (!finished)
{
if (sw.ElapsedMilliseconds > 500)
{
sw.Restart();
//0.5秒未完成處理
}
}
if (sw.ElapsedMilliseconds > 7000)
{
senddata.clear();
dt.Dispose();//7秒后自刪
}
};
}
public FunctionRquestData()
{
sw.Start();
checktimeout();
}
}
uj5u.com熱心網友回復:
定時器用System.Threading.Timer好點把
uj5u.com熱心網友回復:
心跳。uj5u.com熱心網友回復:
我的意思就是每隔1秒發送一次請求,比如請求開始下載,收到開始下載的應答或者發送5次還沒有收到應答就超時
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/130321.html
標籤:C#
上一篇:函式執行結果回傳型別
