using NewLife.Data;
using NewLife.Messaging;
namespace NewLife.Net;
/// <summary>增强TCP客户端(å议模å¼çš„æ¶ˆæ¯æ³µä¸Žå¸§å®šç•Œäº¤ä»˜ï¼‰</summary>
/// <remarks>
/// <para>å议模å¼ä¸‹æ•°æ®ç»æ•°æ®ç®¡é“å®šç•Œï¼Œç”±æ¶ˆæ¯æ³µé€å¸§äº¤ä»˜ã€‚æµå¼ä¸“有é…置(最大残留ã€å•帧上é™ã€æ•´å¸§æ¨¡å¼ï¼‰ã€å¹¶å‘æ´¾å‘ä¿¡å·é‡
/// 与消æ¯äº¤ä»˜å…¥å£ï¼ˆ<see cref="OnMessageAsync"/> ç‰ï¼‰éšæœ¬ç±»ï¼Œä¸å†æ”¾åˆ° <see cref="SessionBase"/>:
/// æ•°æ®æŠ¥ä¼šè¯æ²¡æœ‰ç²˜åŒ…与定界问题,这些æˆå‘˜åœ¨å®ƒé‚£é‡Œåªä¼šæ˜¯"未使用"。</para>
/// <para>æ•°æ®æµï¼šæŽ¥æ”¶çޝ → 入站管é“ï¼ˆè§ TcpSession.Receive)→ MessagePump 定界 → <see cref="OnMessageAsync"/>(事件链与匹é…交付);
/// 关闿—¶å…ˆåœæ³µå¹¶é™æ—¶æŽ’空在途帧(<see cref="PumpDrainTimeout"/>),ä¿è¯å¯¹ç«¯â€œå‘完å³å…³â€æ—¶æœ€åŽä¸€æ¡æ¶ˆæ¯ä¸ä¸¢ã€‚</para>
/// </remarks>
public partial class TcpSession
{
#region 属性
/// <summary>æ¶ˆæ¯æ³µæœ€å¤§ç¼“å˜å—节数(å议模å¼ä¸‹æ— 法定界的残余上é™ï¼‰ï¼Œé»˜è®¤ 1M。0 表示ä¸é™åˆ¶</summary>
/// <remarks>残余达到上é™è¯´æ˜Žå¯¹ç«¯æ•°æ®ä¸Žåè®®ä¸åŒ¹é…或已æŸåï¼Œæ¶ˆæ¯æ³µéšå³æŠ¥é”™å¹¶å…³é—会è¯ï¼Œé¿å…连接僵æ»</remarks>
public Int32 MaxCache { get; set; } = 1024 * 1024;
/// <summary>整帧模å¼ä¸‹çš„å•帧长度上é™ï¼Œé»˜è®¤ 16M。0 表示ä¸é™åˆ¶</summary>
/// <remarks>ä»… <see cref="RequireFullFrame"/> 为 true 时生效:整帧解æžè¦æ±‚整个帧驻留内å˜ï¼Œæœ¬ä¸Šé™æ˜¯å•连接的内å˜å®‰å…¨é˜€</remarks>
public Int32 MaxFrameSize { get; set; } = 16 * 1024 * 1024;
/// <summary>æ¶ˆæ¯æ³µæ˜¯å¦è¦æ±‚整帧完整æ‰äº§å‡ºã€‚默认 false(头部到é½å³äº¤ä»˜ï¼Œä½“å¯ä¸ºæµå¼ï¼‰</summary>
/// <remarks>åœ¨æ¶ˆæ¯æ³µä»»åŠ¡ä¸ŠåŒæ¥æ¶ˆè´¹æµå¼ä½“的实现应é‡å†™ä¸º true:å¦åˆ™å¤§å¸§ä¼šåœ¨äº‹ä»¶å†…åŒæ¥ç‰å¾…åŽç»æ•°æ®ï¼Œå ç”¨çº¿ç¨‹æ± çº¿ç¨‹</remarks>
protected virtual Boolean RequireFullFrame => false;
/// <summary>关闿—¶ç‰å¾…在途帧交付完æˆçš„上é™ï¼ˆæ¯«ç§’),默认 1000。0 表示ä¸ç‰å¾…</summary>
/// <remarks>
/// <para>æ•°æ®ç”±æŽ¥æ”¶çŽ¯å†™å…¥ç®¡é“ã€æ¶ˆæ¯æ³µå¼‚æ¥äº¤ä»˜ï¼Œè€Œå…³é—(å«å¯¹ç«¯ FIN 的被动关é—ï¼‰åœ¨æŽ¥æ”¶çŽ¯ä¸ŠåŒæ¥æŽ¨è¿›ï¼š
/// ä¸ç‰åœ¨é€”交付直接关é—,会把“已读入管é“但尚未交给上层â€çš„帧连åŒå…³é—一起丢掉。
/// 对端“å‘完å³å…³â€æ—¶æœ€åŽä¸€æ¡æ¶ˆæ¯æœ€å…ˆå—æŸï¼ˆå¦‚ MQTT çš„ DISCONNECT 丢失,上层把æ£å¸¸æ–开误判为异常æ–开并误å‘é—嘱)。</para>
/// <para>关闿µç¨‹å…ˆå–消挂起读å–,å†ç‰å¾…泵退出(泵退出å‰ä¼šæŠŠå·²è¯»å‡ºçš„帧交付完),最多ç‰å¾…本上é™ï¼›
/// 处ç†å™¨é•¿æ—¶é—´ä¸è¿”回时ä¸å†ç‰å¾…,按剩余æµç¨‹å…³é—。</para>
/// </remarks>
public Int32 PumpDrainTimeout { get; set; } = 1000;
#endregion
#region 接收æµç¨‹
/// <summary>å¯åŠ¨æŽ¥æ”¶å¤„ç†ã€‚å议模å¼å…ˆå¯åŠ¨æ¶ˆæ¯æ³µï¼ˆå…ˆäºŽæŽ¥æ”¶çŽ¯ï¼Œé¦–ä¸ªæ•°æ®åˆ°è¾¾å‰å°±ç»ªï¼‰</summary>
/// <remarks>ä»…æµå¼ä¼šè¯æœ‰æ¶ˆæ¯æ³µï¼šæ•°æ®ç»æ•°æ®ç®¡é“定界åŽé€å¸§äº¤ä»˜ï¼ŒæŽ¥æ”¶çŽ¯æ”¶åˆ°çš„åŽŸå§‹å—节ä¸å†è¿›äº‹ä»¶ï¼ˆè§ <see cref="RawReceiveTaken"/>)</remarks>
protected override void StartReceiveFlow()
{
if (Protocol == null) return;
if (AutoReceive) StartMessagePump();
else WriteLog("Protocol mode requires automatic receive (AutoReceive). The message pump is not started in pull mode, so raw bytes are received.");
}
/// <summary>åœæ¢æŽ¥æ”¶å¤„ç†ã€‚关闿µç¨‹å¼€å¤´å…ˆåœæ¶ˆæ¯æ³µï¼ˆå–消挂起读å–),éšåŽå…³é—处ç†å™¨é“¾ä¸Žä¼šè¯</summary>
protected override void StopReceiveFlow() => StopMessagePump();
/// <summary>åœæ¢æŽ¥æ”¶å¤„ç†ï¼ˆå¼‚æ¥ï¼‰ã€‚å–æ¶ˆæŒ‚起读å–å¹¶ç‰å¾…在途帧交付完æˆï¼Œä¿è¯åœ¨é€”帧先于关é—交付给上层</summary>
protected override Task StopReceiveFlowAsync() => StopMessagePumpAsync();
/// <summary>æœ¬è½®åŽŸå§‹æ•°æ®æ˜¯å¦å·²è¢«æ¶ˆæ¯æ³µæŽ¥ç®¡</summary>
/// <remarks>å议模å¼ä¸‹æ•°æ®ç»æ•°æ®ç®¡é“定界交付,接收环ä¸å†æŠŠåŽŸå§‹å—èŠ‚æŠ›ç»™äº‹ä»¶ï¼›æ‹‰å–æ¨¡å¼ï¼ˆæ— 泵)时ä»èµ°äº‹ä»¶</remarks>
protected override Boolean RawReceiveTaken => _pumpObserver != null;
/// <summary>销æ¯èµ„æº</summary>
/// <param name="disposing">是å¦é‡Šæ”¾æ‰˜ç®¡èµ„æº</param>
protected override void Dispose(Boolean disposing)
{
base.Dispose(disposing);
// åªé‡Šæ”¾ã€ä¸ç½®ç©ºï¼šç½®ç©ºåŽå¹¶å‘任务的 ??= 会新建“满é¢â€ä¿¡å·é‡ï¼Œå…¶ Release 直接抛 SemaphoreFullException。
// ä¿ç•™å·²é‡Šæ”¾å®žä¾‹ï¼Œè¿Ÿåˆ°çš„ Release 得到 ObjectDisposedException,由收尾逻辑按æ£å¸¸æ—¶åºå¿½ç•¥
_concurrency?.Dispose();
}
#endregion
#region æ¶ˆæ¯æ³µ
private CancellationTokenSource? _pumpCts;
/// <summary>泵任务的观察ç»ä½“。å˜çš„æ˜¯ ContinueWith ç»ä½“è€Œéžæ³µæœ¬ä½“ï¼šä»…ç”¨äºŽè§‚å¯Ÿå¤±è´¥ï¼Œä»¥åŠæ ‡è®°â€œå议模å¼å·²å¯åЍâ€ï¼ˆåœæ¢æ—¶æ¸…空)</summary>
private Task? _pumpObserver;
/// <summary>æ³µæœ¬ä½“ä»»åŠ¡ã€‚å…³é—æ—¶ç‰å¾…在途帧交付完æˆç”¨ï¼ˆè§‚察ç»ä½“ä¸Žæ³µæœ¬ä½“å®Œæˆæ—¶åºä¸åŒï¼Œä¸å¯ç”¨äºŽç‰å¾…)</summary>
private Task? _pumpRunTask;
/// <summary>当å‰å¼‚æ¥æµæ˜¯å¦å¤„äºŽæ¶ˆæ¯æ³µå†…。用于识别泵内关é—(处ç†å™¨å†…主动关é—ã€æ³µå†…报错关é—),é¿å…ç‰å¾…泵自身退出</summary>
private readonly PumpFlag _inPump = new();
/// <summary>å¯åŠ¨æ¶ˆæ¯æ³µã€‚å议模å¼ï¼ˆ<see cref="SessionBase.Protocol"/> éžç©ºï¼‰ä¸‹ç”±æ‰“å¼€æµç¨‹ä¸ŽæœåŠ¡ç«¯ä¼šè¯å¯åЍæµç¨‹è°ƒç”¨</summary>
/// <remarks>首次访问数æ®ç®¡é“ç¡®ä¿å…¶åœ¨æŽ¥æ”¶çޝå¯åЍå‰å°±ç»ªã€‚调用方须ä¿è¯æ—¶åºï¼ˆæ¯æ¬¡ä¼šè¯ç”Ÿå‘½å‘¨æœŸè‡³å¤šä¸€æ¬¡ï¼‰</remarks>
protected void StartMessagePump()
{
var codec = Protocol;
if (codec == null) return;
// 触建数æ®ç®¡é“(接收环å¯åЍå‰å°±ç»ªï¼Œé¦–个数æ®åˆ°è¾¾å³å¯æŠ•递)
var reader = Pipe.Reader;
var cts = new CancellationTokenSource();
_pumpCts = cts;
var task = PumpAsync(new MessagePump(codec) { MaxCache = MaxCache, RequireFullFrame = RequireFullFrame, MaxFrameSize = MaxFrameSize }, reader, cts.Token);
_pumpRunTask = task;
// è§‚å¯Ÿæ³µä»»åŠ¡ï¼šæ³µå†…å¼‚å¸¸è‹¥æ— äººè§‚å¯Ÿä¼šè¢«é™é»˜åžæŽ‰ï¼Œè¡¨çŽ°ä¸ºâ€œè¿žæŽ¥è¿˜åœ¨ä½†å†ä¹Ÿæ”¶ä¸åˆ°æ¶ˆæ¯â€ï¼Œæžéš¾å®šä½
_pumpObserver = task.ContinueWith(
t =>
{
try
{
if (t.IsFaulted) OnError("MessagePump", t.Exception!.GetBaseException());
}
catch { }
},
CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
}
/// <summary>åœæ¢æ¶ˆæ¯æ³µã€‚å–æ¶ˆæŒ‚起读å–,泵任务éšåŽè‡ªè¡Œé€€å‡ºï¼ˆæ•°æ®ç®¡é“完æˆåŒæ ·å”¤é†’读å–)</summary>
private void StopMessagePump()
{
var cts = Interlocked.Exchange(ref _pumpCts, null);
if (cts != null)
{
cts.Cancel();
cts.Dispose();
}
// 清空“泵已å¯åŠ¨â€æ ‡è®°ï¼šRawReceiveTaken 以本生命周期是å¦å·²èµ·æ³µä¸ºå‡†ã€‚
// 䏿¸…ä¼šè®©æ ‡å¿—åœ¨æ³µé€€å‡ºåŽæ’真——åŽç»æŽ¥æ”¶åˆ¤æ–仿Œ‰â€œæ•°æ®å·²äº¤ç»™æ³µâ€é™é»˜ä¸¢å¼ƒåŽŸå§‹å—节
_pumpObserver = null;
_pumpRunTask = null;
}
/// <summary>åœæ¢æ¶ˆæ¯æ³µï¼ˆå¼‚æ¥ï¼‰ã€‚å–æ¶ˆæŒ‚起读å–,并ç‰å¾…在途帧交付完æˆï¼Œé¿å…å…³é—å‰å·²è¯»å‡ºçš„帧被丢弃</summary>
/// <remarks>
/// <para>å–æ¶ˆåªä½œç”¨äºŽæŒ‚起读å–:读å–已完æˆçš„帧ä»ä¼šè¢«æ³µäº¤ä»˜ï¼Œå› æ¤ç‰å¾…泵退出å³å¯ä¿è¯è¿™äº›å¸§å…ˆäºŽå…³é—交付给上层。</para>
/// <para>泵内主动关é—(处ç†å™¨å†…ã€æ³µå†…报错)ä¸å¾—ç‰å¾…自身退出,å¦åˆ™è¦ç‰åˆ°ä¸Šé™ï¼Œç›´æŽ¥è¿”回。</para>
/// </remarks>
/// <returns>泵收尾任务</returns>
protected virtual async Task StopMessagePumpAsync()
{
var run = Interlocked.Exchange(ref _pumpRunTask, null);
StopMessagePump();
var timeout = PumpDrainTimeout;
if (run == null || run.IsCompleted || timeout <= 0 || _inPump.Value) return;
// 在途帧交付通常微秒级完æˆï¼›æœ¬ç‰å¾…是处ç†å™¨é•¿æ—¶é—´ä¸è¿”回时的兜底,超时åŽä¸å†ç‰å¾…
var done = await Task.WhenAny(run, Task.Delay(timeout)).ConfigureAwait(false);
if (done != run) return;
// 观察泵任务的异常,é¿å…æ— äººæ¶ˆè´¹çš„æ•…éšœä»»åŠ¡å †ç§¯
try { await run.ConfigureAwait(false); } catch { }
}
/// <summary>æ¶ˆæ¯æ³µå¾ªçŽ¯ã€‚å®šç•Œæ¶ˆæ¯å¸§å¹¶é€å¸§äº¤ä»˜ï¼›åŒè¿žæŽ¥æ¶ˆæ¯ä¸²è¡Œå¤„ç†</summary>
/// <param name="pump">消æ¯å¸§æ³µ</param>
/// <param name="reader">æ•°æ®ç®¡é“读å–器</param>
/// <param name="cancellationToken">å–æ¶ˆé€šçŸ¥ï¼ˆä¼šè¯å…³é—)</param>
private async Task PumpAsync(MessagePump pump, PipeReader reader, CancellationToken cancellationToken)
{
// 先让出一次å†ç½®æ ‡è®°ï¼šå¼‚æ¥æµæ ‡è®°è‹¥åœ¨åŒæ¥å‰ç¼€èµ‹å€¼ï¼Œä¼šéšæ‰§è¡Œä¸Šä¸‹æ–‡æ³„æ¼åˆ°å¯åŠ¨ä¼šè¯çš„调用方,
// 之åŽåœ¨åŒä¸€çº¿ç¨‹ä¸Šå‘生的关é—会被误判为“泵内关é—â€è€Œè·³è¿‡ç‰å¾…,丢帧照旧
await Task.Yield();
// æ ‡è®°å½“å‰å¼‚æ¥æµå¤„于泵内:泵内(å«å¤„ç†å™¨ï¼‰ä¸»åЍ关é—ä¼šè¯æ—¶ä¸å¾—ç‰å¾…泵自身退出
_inPump.Value = true;
// 䏿Œ‰å–消令牌æå‰é€€å‡ºï¼šå–消åªåº”终æ¢â€œç‰å¾…æ–°æ•°æ®â€ï¼Œå·²åˆ°è¾¾å¹¶å†™å…¥ç®¡é“的帧ä»è¦äº¤ä»˜å®Œå†é€€å‡ºã€‚
// 循环é 读å–结果终æ¢â€”â€”æ— æ•°æ®å¯è¯»æ—¶çš„å–æ¶ˆä»¥ OperationCanceledException 逃出,由下方æ•获åŽé€€å‡ºã€‚
// å之(读到å³é€€ï¼‰ä¼šæŠŠâ€œå¯¹ç«¯å‘完å³å…³â€æ—¶å·²åˆ°è¾¾çš„æœ€åŽä¸€æ¡æ¶ˆæ¯è¿žåŒå…³é—一起丢掉。
while (true)
{
IMessage? message;
try
{
message = await pump.ReadAsync(reader, cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
break;
}
catch (Exception ex)
{
// å…³é—å·²åœ¨è¿›è¡Œï¼ˆä»¤ç‰Œå·²å–æ¶ˆï¼‰ï¼šè¯»å–失效éšå…³é—一并收尾,ä¸å†å½“ä½œæ•°æ®æµæ•…障报错与关é—,
// å¦åˆ™å…³é—æµç¨‹é‡Šæ”¾ç®¡é“åŽæ³µçš„æ”¶å°¾è¯»å–ä¼šåˆ·å‡ºæ— æ„义的 MessagePumpError
if (cancellationToken.IsCancellationRequested) break;
OnError("MessagePump", ex);
// æ•°æ®æµä¸å¯æ¢å¤ï¼ˆå议错误/IO 异常):关é—会è¯ï¼Œé¿å…åŠå¼€è¿žæŽ¥åƒµæ»
Close("MessagePumpError");
break;
}
// æ•°æ®ç®¡é“完æˆï¼ˆè¿žæŽ¥å…³é—):退出
if (message == null) break;
// 有匹é…队列时,入站消æ¯éƒ½å¯èƒ½è¢«é…对交付给ç‰å¾…方:ç‰å¾…方在事件链之åŽè¿˜è¦å¼‚æ¥æ¶ˆè´¹åŒä¸€ä»½ä½“,
// 而æµå¼ä½“ä¸èƒ½è¢«äºŒæ¬¡è¯»ï¼ˆæ³µä¼šç»§ç»è¯»åŒä¸€ PipeReader,导致å•è¯»è€…å†²çªæˆ–把下一帧å—节当æˆä½“ï¼‰ï¼Œå› æ¤å…ˆç‰©åŒ–为内å˜ä½“。
// ä¸èƒ½ä¾èµ– message.Replyâ€”â€”æ— æ–¹å‘ä½å议(如 LengthFieldCodec çš„æ’真 matcher)æ’为 false,会让ç‰å¾…方拿到æµå¼ä½“而串包
if (MatchQueue != null && message.Body is { IsStreaming: true })
{
try
{
var all = await message.Body.ReadAllAsync(cancellationToken).ConfigureAwait(false);
message.SetBody(all);
}
catch (OperationCanceledException)
{
message.TryDispose();
continue;
}
catch (Exception ex)
{
// æµå¼ä½“读满失败(对端åŠé€”æ–å¼€/ç®¡é“æ•…éšœï¼‰ï¼šæ•°æ®æµå·²ä¸å¯æ¢å¤ï¼Œä¸Žå¸§å±‚读失败åŒå£å¾„å…³é—会è¯ã€‚
// 异常若å‘上逃出泵任务,ç»ä½“åªè®°æ—¥å¿—ä¸å…³ä¼šè¯ï¼Œè¡¨çŽ°ä¸ºâ€œè¿žæŽ¥è¿˜åœ¨ã€æ¶ˆæ¯ä¸å†åˆ°è¾¾ã€ä¹Ÿä¸è§¦å‘å…³é—â€çš„åŠæ»æ€
message.TryDispose();
OnError("MessagePump", ex);
Close("MessagePumpError");
break;
}
}
// 并行模å¼ï¼šå…ˆç‰©åŒ–æµå¼ä½“ï¼ˆä¸€æ¬¡æ‹·è´æ¢å¹¶è¡Œå®‰å…¨ï¼‰ï¼Œä¿¡å·é‡çº¦æŸå¹¶å‘åŽæ´¾å‘;处ç†é¡ºåºä¸å®šï¼ˆSRMP 按åºåˆ—å·é…对)
if (MaxConcurrency > 1)
{
if (message.Body is { IsStreaming: true })
{
try
{
var all = await message.Body.ReadAllAsync(cancellationToken).ConfigureAwait(false);
message.SetBody(all);
}
catch (OperationCanceledException)
{
message.TryDispose();
continue;
}
catch (Exception ex)
{
// åŒåŒ¹é…队列分支:æµå¼ä½“è¯»æ»¡å¤±è´¥å³æ•°æ®æµä¸å¯æ¢å¤ï¼Œä¸¢å¼ƒæ¶ˆæ¯å¹¶å…³é—会è¯
message.TryDispose();
OnError("MessagePump", ex);
Close("MessagePumpError");
break;
}
}
try
{
await Concurrency.WaitAsync(cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
message.TryDispose();
break;
}
catch (ObjectDisposedException)
{
// 会è¯é”€æ¯ï¼šå¹¶å‘ä¿¡å·é‡å·²é‡Šæ”¾ï¼Œæ¶ˆæ¯æ— 人处ç†
message.TryDispose();
break;
}
// Task.Run æ´¾å‘:async æ–¹æ³•é¦–æ®µåŒæ¥æ‰§è¡Œï¼Œé¡»çœŸæ£åˆ‡æ¢çº¿ç¨‹æ± ,å¦åˆ™åŒæ¥å¤„ç†å™¨ä¼šé˜»å¡žæ³µå¾ªçޝ
_ = Task.Run(() => ProcessMessageAsync(message, cancellationToken, true));
continue;
}
// 串行模å¼ï¼šåŒè¿žæŽ¥ä¾æ¬¡å¤„ç†ï¼ˆå‰ä¸€æ¡æ”¶å°¾åŽæ‰è¯»ä¸‹ä¸€å¸§ï¼‰
await ProcessMessageAsync(message, cancellationToken, false).ConfigureAwait(false);
}
}
/// <summary>处ç†å•个消æ¯ï¼šç»Ÿä¸€è¿›å…¥äº‹ä»¶é“¾ï¼ˆå¯è§‚测)→ å“应å°è¯•匹é…交付 → æ”¶å°¾</summary>
/// <param name="message">消æ¯</param>
/// <param name="cancellationToken">å–æ¶ˆé€šçŸ¥</param>
/// <param name="releaseSlot">完æˆåŽæ˜¯å¦é‡Šæ”¾å¹¶å‘ä¿¡å·é‡ï¼ˆå¹¶è¡Œæ´¾å‘为 true)</param>
/// <remarks>
/// <para>交付收尾:未交付ç‰å¾…方的消æ¯ä¸¢å¼ƒæœªè¯»è´Ÿè½½å¯¹é½å¸§å°¾ï¼ŒéšåŽé‡Šæ”¾ï¼›å‘½ä¸äº¤ä»˜çš„æ¶ˆæ¯ç”±ç‰å¾…方释放。</para>
/// <para>并行模å¼ï¼ˆ<see cref="SessionBase.MaxConcurrency"/> 大于1ï¼‰ä¸‹ç”±ç‹¬ç«‹ä»»åŠ¡è°ƒç”¨ï¼Œå¼‚å¸¸ç»Ÿä¸€ç» <see cref="SessionBase.OnError"/> 上报,ä¸å‘任务外部抛出。</para>
/// </remarks>
private async Task ProcessMessageAsync(IMessage message, CancellationToken cancellationToken, Boolean releaseSlot)
{
try
{
var delivered = false;
try
{
await OnMessageAsync(message).ConfigureAwait(false);
// 事件链(å¯è§‚测)å¯èƒ½å·²åœ¨å¤„ç†å™¨å†…读空消æ¯ä½“;命ä¸é…对的ç‰å¾…æ–¹è¿˜è¦æ¶ˆè´¹åŒä¸€ä»½ä½“,
// äº¤ä»˜å‰æŠŠå†…å˜æ¨¡å¼ä½“å¤ä½åˆ°èµ·ç‚¹ï¼ˆæµå¼ä½“ä¸å‚与é…对交付,ä¸å¯é‡æ”¾ï¼‰
if (message.Body is { IsStreaming: false } body) body.Reset();
delivered = TryMatchResponse(message);
}
catch (OperationCanceledException) { }
catch (Exception ex)
{
OnError("OnMessage", ex);
}
finally
{
// 交付收尾:未交付ç‰å¾…方的消æ¯ä¸¢å¼ƒæœªè¯»è´Ÿè½½å¯¹é½å¸§å°¾ï¼ŒéšåŽé‡Šæ”¾
if (!delivered)
{
try
{
await MessagePump.DiscardAsync(message, cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException) { }
finally
{
message.TryDispose();
}
}
}
}
catch (Exception ex)
{
// å…•åº•ï¼šé˜²æ¢ fire-and-forget 任务异常未观察
OnError("ProcessMessage", ex);
message.TryDispose();
}
finally
{
// 会è¯é”€æ¯æ—¶ä¿¡å·é‡å¯èƒ½å·²é‡Šæ”¾ï¼šä»»åŠ¡æ”¶å°¾æ™šäºŽ Dispose 属æ£å¸¸æ—¶åºï¼Œå¿½ç•¥è¯¥å¼‚常
if (releaseSlot)
{
try { Concurrency.Release(); }
catch (ObjectDisposedException) { }
}
}
}
private SemaphoreSlim? _concurrency;
/// <summary>å¹¶å‘ä¿¡å·é‡ã€‚并行模å¼ï¼ˆ<see cref="SessionBase.MaxConcurrency"/> 大于1)下约æŸåŒè¿žæŽ¥å¹¶å‘å¤„ç†æ•°ï¼Œç‰å¾…æ—¶å½¢æˆèƒŒåŽ‹</summary>
/// <remarks>惰性创建åŽ<b>åªé‡Šæ”¾ã€ä¸ç½®ç©º</b>:置空åŽè¿Ÿåˆ°çš„å½’è¿˜ä¼šç» <c>??=</c> 新建出“满é¢â€ä¿¡å·é‡ï¼Œ
/// å…¶ <c>Release</c> 抛 <see cref="SemaphoreFullException"/>ï¼›ä¿ç•™å·²é‡Šæ”¾å®žä¾‹åˆ™åªæŠ›
/// <see cref="ObjectDisposedException"/>,由收尾逻辑按æ£å¸¸æ—¶åºå¿½ç•¥ã€‚</remarks>
private SemaphoreSlim Concurrency => _concurrency ??= new SemaphoreSlim(MaxConcurrency, MaxConcurrency);
#endregion
#region 消æ¯äº¤ä»˜
/// <summary>å°è¯•把å“应消æ¯åŒ¹é…ç»™ç‰å¾…ä¸çš„请求(å议模å¼ï¼‰ã€‚命ä¸åˆ™äº¤ä»˜ç‰å¾…方,跳过收尾</summary>
/// <param name="message">收到的消æ¯</param>
/// <returns>是å¦å·²åŒ¹é…交付</returns>
/// <remarks>
/// <para>æ— åŒ¹é…队列(未å‘过ç‰å¾…è¯·æ±‚ï¼‰æˆ–æ— é…对å议时快速返回,ä¸äº§ç”Ÿé¢å¤–开销;
/// æ¶ˆæ¯æ˜¯å¦å¯é…对由åè®® matcher 判定(如 SRMP è¦æ±‚åº”ç”æ¶ˆæ¯+åºåˆ—å·ç›¸ç‰ï¼›æ— æ–¹å‘åè®®å¯ç”¨æ’真 matcher)。</para>
/// <para>æµå¼è´Ÿè½½åœ¨äº‹ä»¶äº¤ä»˜å‰ç‰©åŒ–ä¸ºå†…å˜æ¨¡å¼ï¼šäº‹ä»¶é“¾å¯è§‚察读å–,ç‰å¾…æ–¹åœ¨ä»»æ„æ—¶æœºå¼‚æ¥æ¶ˆè´¹ï¼ˆä¸€æ¬¡æ‹·è´æ¢æ£ç¡®æ€§ï¼‰ã€‚
/// æœªå‘½ä¸æ—¶æ¶ˆæ¯æŒ‰æ™®é€šæµç¨‹æ”¶å°¾ï¼Œè´Ÿè½½éšæ¶ˆæ¯å½’还。</para>
/// </remarks>
private Boolean TryMatchResponse(IMessage message) => Matcher.TryMatch(this, Protocol, message);
/// <summary>收到消æ¯ï¼ˆå¼‚æ¥ï¼‰ã€‚å议模å¼ï¼ˆ<see cref="SessionBase.Protocol"/> éžç©ºï¼‰ä¸‹ç”±æ¶ˆæ¯æ³µé€å¸§è°ƒç”¨</summary>
/// <param name="message">消æ¯ï¼ˆå¤´éƒ¨å—段就ä½ã€ä½“已绑定)</param>
/// <remarks>
/// <para>默认触å‘åŒæ¥ <see cref="SessionBase.Received"/> 事件链。处ç†å™¨è¿”å›žåŽæ¶ˆæ¯è¿›å…¥æ”¶å°¾ï¼šæœªè¯»ä½“被丢弃对é½å¸§å°¾ã€æ¶ˆæ¯é‡Šæ”¾ã€‚</para>
/// <para>需è¦å¼‚æ¥è¯»å–æµå¼ä¸»ä½“的场景,继承会è¯é‡å†™æœ¬æ–¹æ³•,在 await 期间消æ¯ä¸Žæ•°æ®çª—å£ä¿æŒæœ‰æ•ˆï¼›åŒæ¥äº‹ä»¶å¤„ç†å™¨å†…éœ€è¦æµå¼æ•°æ®æ—¶è¯·å…ˆç‰©åŒ–(<see cref="LimitedReader.ReadAllAsync"/>ï¼Œæ•°æ®æœªåˆ°é½ä¼šç‰å¾…——串行è¯ä¹‰ä¸‹æ£ç¡®ï¼‰ï¼Œæˆ–物化åŽäº¤ç»™åŽå°å¼‚æ¥é“¾å¤„ç†ã€‚</para>
/// </remarks>
protected virtual ValueTask OnMessageAsync(IMessage message)
{
OnMessage(message);
return default;
}
/// <summary>收到消æ¯ã€‚å议模å¼ï¼ˆ<see cref="SessionBase.Protocol"/> éžç©ºï¼‰ä¸‹ç”±æ¶ˆæ¯æ³µé€å¸§è°ƒç”¨</summary>
/// <param name="message">消æ¯ï¼ˆå¤´éƒ¨å—段就ä½ã€ä½“已绑定)</param>
/// <remarks>
/// <para>æž„é€ æŽ¥æ”¶äº‹ä»¶å‚æ•°å¹¶è¿›å…¥ <see cref="SessionBase.OnReceive"/> 事件链;消æ¯ä½“æœªè¯»éƒ¨åˆ†ç”±æ¶ˆæ¯æ³µåœ¨äº¤ä»˜åŽä¸¢å¼ƒå¯¹é½ä¸‹ä¸€å¸§ã€‚</para>
/// <para>äº‹ä»¶å‚æ•°çš„ <see cref="ReceivedEventArgs.Packet"/> 为消æ¯è´Ÿè½½è§†å›¾ï¼ˆæ•´å¸§å¿«è·¯å¾„),æµå¼æ¨¡å¼ä¸‹ä¸º null;与消æ¯åŒç”Ÿå‘½å‘¨æœŸï¼ˆå¤„ç†å™¨è¿”回åŽå¤±æ•ˆï¼‰ï¼Œéœ€è¦ç•™å˜è¯·å…ˆç‰©åŒ–æˆ–åˆ‡å‡ºå…±äº«å¥æŸ„ã€‚ä¸šåŠ¡è¯·ç»Ÿä¸€ç» <see cref="ReceivedEventArgs.Message"/> 读å–头部与æµå¼ä½“。</para>
/// </remarks>
protected virtual void OnMessage(IMessage message)
{
var e = ReceivedEventArgs.Rent();
try
{
e.Local = Local.Address;
e.Remote = Remote.EndPoint;
e.Packet = message.Payload;
e.Message = message;
OnReceive(e);
}
finally
{
ReceivedEventArgs.Return(e);
}
}
#endregion
}
|