SignalR 设计理念(二)
实现客户端和服务器端的实时通讯.
前言:
客户端方法忽略大小写,主要原因基于是URL对大小写不敏感的问题,开发者之间为了更好的协同开发,定下的开发者协议。
问题阐述
- 客户端数量不确定!
- 同一个用户的客户端数量不确定(一个用户可以多处登陆)!
- 客户端连接的渠道不确定(应用程序连接、Web普通连接、WebSocket连接等)!
- 同一个用户的连接渠道不一定!
针对以上问题,你会如何设计服务器架构?
SignalR 采用 管道通讯 作为连接消息通道,使用 分配器 对消息适配(基于持久化连接抽象类
PersistentConnection
实现)。
问:
- 管道数如何区分连接渠道? 1
举一反三:
- 客户端和服务器之间,消息是如何传递的?
核心代码:
public abstract class PersistentConnection { //持久化连接 【部分代码】 public virtual Task ProcessRequest(HostContext context) { if (context == null) { throw new ArgumentNullException("context"); } if (!_initialized) { throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, Resources.Error_ConnectionNotInitialized)); } if (IsNegotiationRequest(context.Request)) { return ProcessNegotiationRequest(context); } else if (IsPingRequest(context.Request)) { return ProcessPingRequest(context); } Transport = GetTransport(context); // 建立运输方式 if (Transport == null) { return FailResponse(context.Response, String.Format(CultureInfo.CurrentCulture, Resources.Error_ProtocolErrorUnknownTransport)); } string connectionToken = context.Request.QueryString["connectionToken"]; if (String.IsNullOrEmpty(connectionToken)) { return FailResponse(context.Response, String.Format(CultureInfo.CurrentCulture, Resources.Error_ProtocolErrorMissingConnectionToken)); } string connectionId; string message; int statusCode; if (!TryGetConnectionId(context, connectionToken, out connectionId, out message, out statusCode)) { return FailResponse(context.Response, message, statusCode); } Transport.ConnectionId = connectionId; // Get the groups token from the request return Transport.GetGroupsToken() .Then((g, pc, c) => pc.ProcessRequestPostGroupRead(c, g), this, context) .FastUnwrap(); } } public class TransportManager : ITransportManager { //运输机管理器 【部分代码】 private readonly ConcurrentDictionary<string, Func<HostContext, ITransport>> _transports = new ConcurrentDictionary<string, Func<HostContext, ITransport>>(StringComparer.OrdinalIgnoreCase); [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Those are factory methods")] public TransportManager(IDependencyResolver resolver) { if (resolver == null) { throw new ArgumentNullException("resolver"); } Register("foreverFrame", context => new ForeverFrameTransport(context, resolver)); Register("serverSentEvents", context => new ServerSentEventsTransport(context, resolver)); Register("longPolling", context => new LongPollingTransport(context, resolver)); Register("webSockets", context => new WebSocketTransport(context, resolver)); } // 注册运行机 (可自定义运输方式) public void Register(string transportName, Func<HostContext, ITransport> transportFactory) { if (String.IsNullOrEmpty(transportName)) { throw new ArgumentNullException("transportName"); } if (transportFactory == null) { throw new ArgumentNullException("transportFactory"); } _transports.TryAdd(transportName, transportFactory); } // 分配运输机 public ITransport GetTransport(HostContext hostContext) { if (hostContext == null) { throw new ArgumentNullException("hostContext"); } string transportName = hostContext.Request.QueryString["transport"]; if (String.IsNullOrEmpty(transportName)) { return null; } Func<HostContext, ITransport> factory; if (_transports.TryGetValue(transportName, out factory)) { return factory(hostContext); } return null; } }
解析:
- 由连接中的
transport
参数区分,有兴趣的朋友可以下载源码深度学习 Microsoft.AspNet.SignalR。?
原文地址:https://www.cnblogs.com/vbing/p/10012765.html
时间: 2024-10-14 21:24:02