一、问题背景
目前公司在互联网产品上需要程序与前端部分要进行一个实时交互,在进行一定程度上的选型后,决定使用socket.io框架进行一个实践,算是公司的一个新的 尝试,也算是给自己增加增长见闻,由于我是做后端以及桌面程序开发,所以前端部分就不细聊,主要是针对桌面程序如何连接socket.io进行一个尝试
二、基本逻辑图
本地应用程序:部署在局域网内(可以联通外网),主要负责相关数据获取
Web浏览器端:跟本地应用程序不是处于同一个网络,请求发起方
中转服务(重点):中转服务集成认证功能,必须经过认证的客户端才允许进行连接,并且对于客户端要有唯一指定的ID进行连接操作
整体思路如以上的流程图,由Web浏览器端开始发起请求,Web浏览器端通过连接中转服务,将信息发送给指定的本地应用程序,应用程序处理完成后,将结果通过原路径进行一个反馈
二、客户端程序开发
客户端SDK采用SocketIoClientDotNet,这是一个github上开源的,可以连接socket.io的客户端,支持.net 3.5及以上,可以方便的帮助我们进行连接socket.io的开发
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
Socket socket = IO.Socket( "ws://192.168.7.4:3000" , new IO.Options()
{
Reconnection = true ,
Cookies = new Dictionary< string , string >() { { "companyId" , GlobalStatic.COMPANY.COMPANY_ID }, { "userId" , GlobalStatic.UserDomain.user.USER_ID } },
Timeout = 60000,
ReconnectionDelay = 1000,
Transports = new List< string >() { "websocket" },
Path = "heart"
});
socket.On(Socket.EVENT_CONNECT, () =>
{
JObject jObject = JObject.Parse(Newtonsoft.Json.JsonConvert.SerializeObject( new
{
companyId = GlobalStatic.COMPANY.COMPANY_ID,
token = GlobalStatic.TOKEN,
hostId = GlobalStatic.HOST_ID,
hostName = GlobalStatic.HOST_NAME,
printerNames = GlobalStatic.HOSTINFO.PrinterName,
source = "assistant" ,
userId = GlobalStatic.UserDomain.user.USER_ID
}));
socket.Emit( "authentication" , jObject);
Debug.WriteLine( "authentication" );
});
socket.On(Socket.EVENT_DISCONNECT, (data) =>
{
Debug.WriteLine( "心跳断开连接" + data);
flag = false ;
OnConnectionStatus?.Invoke(flag);
socket.Disconnect();
});
socket.On( "authenticated" , (obj) =>
{
flag = true ;
OnConnectionStatus?.Invoke(flag);
Debug.WriteLine( "心跳认证成功:" + obj);
});
socket.On( "unauthorized" , (obj) =>
{
Debug.WriteLine( "心跳认证失败" + obj);
socket.Disconnect();
});
|
SocketIoClientDotNet注意点:
- emit的数据必须为字符串或者JObject(Newtonsoft.Json中的)
- 从实际情况来看,内部每个On的监听都是维护了一个线程,所有如果是不想要阻塞的话,那在on的方法中还需要自己起线程去完成
- 如果不在options中设置AutoConnect=false的话,那实例化socket成功之后就会进行connect动作
三、关于SocketIoClientDotNet坑的问题
在实际的使用过程中,偶然发现在程序开了很久 之后,线程数会一直增多,尝试调节各种参数都毫无作用,最后只能无奈的跟踪源码部分,在Thread文件夹下找到Heartbeat_net35.cs文件中,发现run方法里的while一直无法跳出去,并且注册DoWork越来越多,如下所示,导致线程越来越多,目前解决办法是将该代码注释掉,还没发现什么问题,如果有哪位知道这段代码作用的话,望告知,谢谢
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
using System;
using System.ComponentModel;
using System.Threading;
namespace Quobject.EngineIoClientDotNet.Thread
{ public class Heartbeat
{
private volatile bool gotHeartbeat = false ;
private BackgroundWorker heartBeatTimer= new BackgroundWorker();
private CancellationTokenSource ts;
private Heartbeat()
{
ts = new CancellationTokenSource();
}
public static Heartbeat Start(Action onTimeout, int timeout)
{
Heartbeat heartbeat = new Heartbeat();
heartbeat.Run(onTimeout, timeout);
return heartbeat;
}
public void OnHeartbeat()
{
gotHeartbeat = true ;
}
private void Run(Action onTimeout, int timeout)
{
heartBeatTimer = new BackgroundWorker();
heartBeatTimer.DoWork += (s, e) =>
{
while (!ts.IsCancellationRequested)
{
System.Threading.Thread.Sleep(timeout);
if (!gotHeartbeat && !ts.IsCancellationRequested)
{
onTimeout();
break ;
}
}
};
heartBeatTimer.RunWorkerAsync();
}
public void Stop()
{
ts.Cancel();
}
}
} |
作者: Mango
出处: http://www.cnblogs.com/OMango/
关于自己:专注.Net桌面开发以及Web后台开发,开始接触微服务、docker等互联网相关