使用windows服务、SignalR实现双工通讯之客户端篇
上一篇文章实现了用windows服务为宿主的SignalR通讯服务端,这一篇将实现用windows服务为宿主的通讯客户端。
废话不多说,放码上来。。。
1、新建一个类库,封装SignalR的客户端相关方法,代码如下:
1 public class SignalRClient 2 { 3 //与服务端的交互 4 5 /// <summary> 6 /// SignalR通讯管道 7 /// </summary> 8 private IHubProxy HubProxy { get; set; } 9 /// <summary> 10 /// SignalR通讯服务端地址 11 /// </summary> 12 private string ServerURI; 13 /// <summary> 14 /// SignalR通讯管道名称 15 /// </summary> 16 private string HubName; 17 /// <summary> 18 /// 当前客户端 19 /// </summary> 20 private ClientInfo Client; 21 private Logger Log = new Logger(LogName.Signalr_Client.ToString()); 22 /// <summary> 23 /// 错误信息备注 24 /// </summary> 25 private string ErrMsgRemark = ""; 26 private JsonSerializerSettings JsonSetting; 27 28 public SignalRClient(string url,string port,string hubName) 29 { 30 //获取到客户端传来的客户端信息 31 JsonSetting = new JsonSerializerSettings(); 32 JsonSetting.NullValueHandling = NullValueHandling.Ignore; 33 this.HubName = hubName; 34 this.ServerURI = "http://" + url + ":" + port + "/signalr"; 35 } 36 private HubConnection SrConnection { get; set; } 37 38 private void RegisterHunFun() 39 { 40 //定义客户端开机设置 41 ErrMsgRemark = "注册Sr通讯管道客户端函数异常!"; 42 try 43 { 44 HubProxy.On(ClientHubFunName.TestClient.ToString(), () => 45 { 46 SrClientHandl.TestClient(); 47 }); 48 HubProxy.On<ClientInfo>(ClientHubFunName.BootSetting.ToString(), (ClientInfo client) => 49 { 50 SrClientHandl.BootSetting(client); 51 }); 52 HubProxy.On<ClientInfo>(ClientHubFunName.ShutdownSetting.ToString(), (ClientInfo client) => 53 { 54 SrClientHandl.ShutdownSetting(client); 55 }); 56 HubProxy.On<ClientInfo>(ClientHubFunName.GetFlowInfo.ToString(), (ClientInfo client) => 57 { 58 SrClientHandl.GetFlowInfo(client); 59 }); 60 HubProxy.On<ClientInfo>(ClientHubFunName.LogTrans.ToString(), (ClientInfo client) => 61 { 62 SrClientHandl.LogTrans(client); 63 }); 64 HubProxy.On<ClientInfo>(ClientHubFunName.PerfectClientAttribute.ToString(), (ClientInfo client) => 65 { 66 this.Client = client; 67 }); 68 } 69 catch (Exception ea) 70 { 71 Log.Error(ErrMsgRemark, ea); 72 throw ea; 73 } 74 } 75 76 private ClientInfo GetCurrentClient() 77 { 78 Client = new ClientInfo(); 79 Client.ClientId = "1111"; 80 return Client; 81 } 82 //客户端连接 83 public async void ConnectAsync() // 84 { 85 Log.Info("进入方法Connect,HubName:" + HubName); 86 try 87 { 88 89 //传给服务端本机信息 90 string clientJson = JsonConvert.SerializeObject(GetCurrentClient(), JsonSetting); 91 Log.Info("进入方法Connect,传输的客户端json:" + clientJson); 92 var querystringData = new Dictionary<string, string>(); 93 querystringData.Add("ClientJson", clientJson); 94 SrConnection = new HubConnection(ServerURI, querystringData); 95 96 SrConnection.Closed += Connection_Closed; 97 HubProxy = SrConnection.CreateHubProxy(this.HubName); 98 99 Log.Info("进入方法Connect1"); 100 RegisterHunFun(); 101 try 102 { 103 await SrConnection.Start(); 104 } 105 catch (Exception ea) 106 { 107 Log.Error("开启SR链接异常!", ea); 108 } 109 110 //调用服务端方法 111 Log.Info("调用服务端方法SendTest"); 112 await HubProxy.Invoke("SendTest", "测试"); 113 Log.Info("链接服务端完毕"); 114 } 115 catch (Exception ea) 116 { 117 /*这里异常会有一个隐性问题,如客户端未启动起来就悲剧了 118 最好办法是加一个定时服务,检测与服务端通信是否打开,未打开就再次开启链接 119 */ 120 Log.Error(ea); 121 } 122 123 } 124 //客户端关闭事件 125 private void Connection_Closed() 126 { 127 //通知服务端下线 128 129 if (SrConnection != null) 130 { 131 SrConnection.Stop(); 132 SrConnection.Dispose(); 133 } 134 } 135 }
上面SrClientHandl类就是封装RegisterHunFun方法里调用的方法,因为有具体工作的相关代码,这里就不上代码了
2、新建windows服务作为客户SignalR宿主,具体代码如下:
1 string srUrl = SignalRContext.Current.ServerIpAddress; 2 string srPort = SignalRContext.Current.ServerPort; 3 string srHub = SignalRContext.Current.HubName; 4 log.Info("srUrl:" + srUrl + ",srPort:" + srPort + ",srHub:" + srHub); 5 SignalRClient srClient = new SignalRClient(srUrl, srPort, srHub); 6 log.Info("开始连接服务端"); 7 srClient.ConnectAsync(); 8 log.Info("连接服务端成功");
3、再补充下,客户端调用服务端方法还是服务端调用客户端开放的方法,双方都可以得到对方方法的返回值的。
这是我服务端的方法:
1 //测试数据传输方法 2 public ClientInfo SendTest(string name) 3 { 4 Log.Info("客户端执行服务端方法,参数name:" + name); 5 Log.Info(" Context.ConnectionId:" + Context.ConnectionId); 6 ClientInfo info = new ClientInfo(); 7 info.ClientName = name; 8 info.ConnId = Context.ConnectionId; 9 return info; 10 }
这是我客户端调用服务端方法的片段:
1 await SrConnection.Start();//开启链接 2 //调用服务端方法 3 Log.Info("调用服务端方法SendTest"); 4 ClientInfo cl = await SrClientHandl.InvokeServerFunAsync<ClientInfo>(ServerHubFunName.SendTest, HubProxy, new object[] { "test" }); 5 Log.Info("得到服务端返回的clientinfo:" + JsonConvert.SerializeObject(cl, JsonSetting));
SrClientHandl.InvokeServerFunAsync方法是我封装的一个客户端调用服务端异步方法,代码如下
1 //异步执行有返回值的服务端方法 2 public async static Task<T> InvokeServerFunAsync<T>(ServerHubFunName fun, IHubProxy hub, params object[] args) 3 { 4 T result = await hub.Invoke<T>(fun.ToString(), args); 5 return result; 6 }
这是日志效果:
暂时还不知道怎么查看当前的SignalR使用的哪种通讯方式,因为客户端不是浏览器,应该不是websocket,如果是长连接不知道实际效率怎么样。。。 有SignalR经验丰富的小伙伴可以和我互动下,一起加油!
至此一切ok了。。。。
安利一下微软提供的Signalr相关页面,有兴趣的可以看下:
https://www.asp.net/signalr/overview/getting-started/introduction-to-signalr