socket.io-client-csharp
socket.io-client-csharp copied to clipboard
断线重连时报错未将对象引用设置到对象的实例。
不好意思,英文太烂,只能用中文提issue了。 最近在测试3.0时,发现有个问题,想向您请教。
服务端是node "socket.io": "^4.0.1", 我的代码使用如下
socketClient = new SocketIO(host, new SocketIOOptions
{
Query = new Dictionary<string, string>
{
{
"token","token"
}
}
});
socketClient.ClientWebSocketProvider = () => new ClientWebSocketManaged();
await socketClient.ConnectAsync();
重连的代码也是参考您的
socketClient.OnDisconnected += async (sender, e) =>
{
while (true)
{
try
{
await socketClient.ConnectAsync();
break;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
await Task.Delay(1000);
}
}
};
我的测试方法是在连接上服务端以后,就禁用网卡,过一段时间再启用网卡,测试是否会自动重连上。 经过多次测试,发现 如果断开的时间短,可以实现预期的重连效果
如果断开的时间太长,则会在OnDisconnected的await socketClient.ConnectAsync();报异常 引发的异常:“System.NullReferenceException”(位于 mscorlib.dll 中) 未将对象引用设置到对象的实例。
同时也可能发生其他状况 1.有时候可能会出现一台主机,会在服务端有两个连接 2.有时候网络通了以后,重连的时候会触发OnConnected,但是马上会触发OnDisconnected,再也无法连接成功。 3.有时候网络断了,无法触发OnDisconnected
希望我的测试能对您有些帮助,希望socket.io-client-csharp能越来越好
感谢你的反馈,但是你的代码流程有部分问题。
目前库默认支持重新连接,因此你不需要手动重新连接,尝试删除这些代码:
while (true)
{
try
{
await socketClient.ConnectAsync();
break;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
await Task.Delay(1000);
}
}
我不确定你所遇到的问题是否都与这有关
我按照您的办法,把上述代码去掉后,确实可以。 但是还有另外一个发现,如果是服务端调用了socket.disconnect, 那么客户端则不会自动重连。 如果是这种情况,有办法可以自动重连吗?
可以看一下这个文档: https://socket.io/docs/v4/client-api/#event-disconnect
OnDisconnect 事件处理函数的参数是一个字符串的值,可以称为 reason,在上述代码中,变量名是 e
客户端主动断开连接时,reason 是 io client disconnect
,服务端断开连接时,reason 是 io server disconnect
这两种断开时,库不会重新连接,因此官方文档中给出示例了,if (reason === "io server disconnect")
同样的,在使用SocketIOClient 时,你需要有类似的操作:
socketClient.OnDisconnected += async (sender, e) =>
{
if (e == "io server disconnect")
await socket.ConnectAsync();
};
我在OnDisconnected测试了下重置Query, socketClient.OnDisconnected += async (sender, e) => { if (e == "io server disconnect") dict["date"] = DateTime.Now.ToString("HH:mm:ss"); socketClient.Options.Query = dict; await socket.ConnectAsync(); }; 我发现服务端socket.handshake.query获取到的日期始终是初次连上的日期,重连上的Query没有更新 不知道是bug还是刻意如此设计?
属于 bug,目前你可以这样管理Query:
socketClient.OnDisconnected += async (sender, e) =>
{
if (e == "io server disconnect")
{
var sio = sender as SocketIO;
// 通过操作来处理,比较麻烦
sio.Router.QueryParams
}
};
下一次更新,将会修复这个问题。感谢你的反馈。
辛苦!下次更新测试验证后我会close。
socketClient.OnDisconnected += async (sender, e) =>
{
if (e == "io server disconnect")
dict["date"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm");
socketClient.Options.Query = dict;
await socket.ConnectAsync();
};
更新到3.03后,这段代码在断开后不会再自动重连,多次测试每次都可以复现。
测试方法:
1.客户端在header里放置连接时间,连接到服务端成功后,禁用网卡,十分钟后启用网卡。启用网卡后,会执行重连。到这里一切正常。
2.因为是测试断联,所以我在服务端设置收到的header里的时间如果超过十分钟,就disconnect。因此步骤1中的重新连接会被服务端disconnect
3.客户端执行OnDisconnected,理想状态应该是header携带最新时间再次连接服务端。 但是在3.0.3中,客户端不会再次重连。 在3.0.2中,大部分情况会重连,偶尔发生不会重连的情况,同时有一定几率抛出异常:无法访问已释放的对象。
可以提供一个可复现的 github repo 吗?只需要上述描述的必要代码即可
好的,我先提供我测试用的代码,处理完手上这点事再提交个repo 我的客户端代码如下,分别使用3.0.3和3.0.2测试过。
public async Task StartConnect()
{
var socketClient = new SocketIO(url);
//兼容win7
socketClient.ClientWebSocketProvider = () => new ClientWebSocketManaged();
var jsonSerializer = new SocketIOClient.Newtonsoft.Json.NewtonsoftJsonSerializer();
jsonSerializer.OptionsProvider = () => new JsonSerializerSettings
{
ContractResolver = new Newtonsoft.Json.Serialization.DefaultContractResolver
{
NamingStrategy = new Newtonsoft.Json.Serialization.CamelCaseNamingStrategy()
}
};
socketClient.JsonSerializer = jsonSerializer;
var dict = new Dictionary<string, string>();
dict["date"] = now;
socketClient.Options.Query = dict;
await socketClient.ConnectAsync();
socketClient.OnDisconnected += async (sender, e) =>
{
if (e == "io server disconnect")
{
try
{
dict["date"] = now;
socketClient.Options.Query = dict;
await socketClient.ConnectAsync();
}
catch (Exception)
{
}
}
};
}
服务端代码用的是node
socketio.on("connection", async (socket: Socket) => {
socket.on('disconnect', function (reason) {
});
let clientdate=socket.handshake.query["date"]
if(){ //clientdate和服务端时间相差十分钟
socket.disconnect(true)
}
});