我正在尝试构建一个使用nkzawa的socket.io-client.java 1.0.0作为节点服务器上的socket.io客户端的android应用程序。
我以前一直在使用0.6.0库,并且它一直在出色地工作,没有任何问题,只是它不正确地支持unicode,因此它促使我更改(或升级?)库来处理该问题。
但是现在,我开始面临另一个问题:android客户端几乎每15秒重新连接一次,因此为该会话设置的所有会话变量(无论是使用会话中间件存储在服务器上还是作为会话成员)服务器上的套接字对象)变得完全冗余,因为它们不再能够被访问。
考虑到客户端有时会在从服务器发送的事件到到达客户端之前的短暂时间间隔内重新连接(就我所知),这确实是个问题,导致事件永远不会完全到达客户端。如果在客户端-服务器通信链的中间突然重置连接,导致连接中断到一半,这将变得更加麻烦。
奇怪的是,仅当将实时Web服务链接(由iisnode托管)与1.0.0库一起使用时(如我之前提到的,0.6.0库都没有发生此问题)时才会发生,但是当我在本地主机上对其进行测试时,则不会。为什么会这样?
无论如何,我尝试将android的超时时间增加到600000,但仍然没有任何反应。
我什至尝试将pingtimeout和pinginterval值增加一倍,但无济于事。
我还尝试在客户端将套接字选项设置为reconnect = false,但这仅阻止了客户端再次尝试重新连接,并且大约15秒后仍然断开连接。
我在网上搜索了很多内容,包括阅读了很多看起来很相似的SO问题,但是我发现的是人们试图找到一种方法来阻止套接字在客户端不活动时自动关闭,但这并不是我面临的问题,所以他们真的帮不上忙。如果我发现很少的帖子谈论同样的问题,那么它要么是一个旧帖子,答案告诉问问问问问问问问问问问问问者升级到一个已久的旧版本的问题,要么问题仍然悬而未决。多年没有答案。
由于该问题仅在尝试在实时Web服务链接上进行测试时才会发生,因此我认为该问题可能是主机方面的问题,但是为什么在使用相同环境但在使用相同环境之前却没有发生此问题呢?库的旧版本?因此,我得出结论认为,不可能从那个角度出发。
关于如何解决此问题的想法已经用尽。有人可以帮忙吗?
这是我的服务器代码:
socket.on("connection", function(conn) {
//console.log("Client is connected\n");
conn.emit("connected", conn.id);
conn.on("disconnect", function() {
socket.emit("disconnected", conn.id);
});
conn.on("userConnected", function(id) {
conn.join(id);
});
...
conn.on("verifyOtp", function(otp) {
//console.log("Client emit - verify OTP\n");
var msg;
var statusCode;
var statusMessage;
/* if ((Date.now() - conn.handshake.sendTime) / 1000 > 60) {
msg = "OTP code is no longer valid";
statusCode = 403;
statusMessage = "Forbidden";
} else*/
if (otp !== conn.handshake.otp) {
msg = "OTP code is incorrect";
// arabicMsg = "الرمز المدخل غير صحيح";
arabicMsg = otp + " " + conn.handshake.otp;
statusCode = 403;
statusMessage = "Forbidden";
} else {
msg = "Verified";
// arabicMsg = "تم التحقيق";
arabicMsg = otp + " " + conn.handshake.otp;
statusCode = 200;
statusMessage = "OK";
}
var res = {
msg: msg,
arabicMsg: arabicMsg,
statusCode: statusCode,
statusMessage: statusMessage
};
//console.log(res.statusCode + " - " + res.statusMessage + "\n");
//console.log(res.msg + "\n");
conn.emit("otpVerificationDone", res);
});
...
conn.on("login", async function(mobile, pass) {
//console.log("Client emit - login\n");
var error;
try {
var req = new sql.Request();
req.input("mobile", sql.Int, mobile);
var q = "select * from users where mobileNo=@mobile";
var results = await req.query(q);
if (results.recordset.length === 0) {
error = {
msg: "This mobile number is not registered",
arabicMsg: "رقم الجوال هذا غير مسجل",
statusCode: 401,
statusMessage: "Unauthorized"
};
conn.emit("loginError", error);
//console.log(error.statusCode + " - " + error.statusMessage + "\n");
//console.log(error.msg + "\n");
} else {
var user = results.recordset[0];
if (bcrypt.compareSync(pass, user.password)) {
var otp = Math.floor(Math.random() * (9999 - 2)) + 1;
otp = otp.toString().padStart(4, '0');
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
otp = "1234";
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
var res = await sendCode(otp, mobile, true);
if (res.err) {
error = {
msg: "Error: Could not send OTP: " + res.err,
statusCode: 500,
statusMessage: "Internal Server Error"
};
conn.emit("loginError", error);
//console.log(error.statusCode + " - " + error.statusMessage + "\n");
//console.log(error.msg + "\n");
} else {
conn.handshake.otp = otp;
conn.handshake.sendTime = res.sendTime;
conn.handshake.user = user;
conn.emit("otpSent");
//console.log("OTP: " + otp + "\n");
}
} else {
error = {
msg: "Incorrect password",
statusCode: 401,
statusMessage: "Unauthorized"
};
conn.emit("loginError", error);
//console.log(error.statusCode + " - " + error.statusMessage + "\n");
//console.log(error.msg + "\n");
}
}
} catch (err) {
error = {
msg: "Error checking if user exists: " + err,
statusCode: 400,
statusMessage: "Bad Request"
};
conn.emit("loginError", error);
//console.log(error.statusCode + " - " + error.statusMessage + "\n");
//console.log(error.msg + "\n");
}
});
conn.on("loginUserInfo", async function() {
//console.log("Client emit - Login user info\n");
// some code to return user info after successful otp verification
});
...
});
这是我目前正在努力处理的事件的代码。
在客户端,正在使用onCreate()方法初始化套接字,并在onResume()方法中注册事件处理程序。它们正在onPause()方法中未注册:
private Socket socket;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
socket = MGasSocket.socket;
socket.connect();
...
}
@Override
protected void onResume() {
super.onResume();
socket.on("connected", connected);
socket.on("disconnected", disconnected);
socket.on("loginError", loginError);
socket.on("otpSent", otpSent);
socket.on("otpVerificationDone", otpVerificationDone);
socket.on("loginSuccess", loginSuccess);
}
@Override
protected void onPause() {
super.onPause();
socket.off();
}
正如我提到的那样,我希望仅当客户端真正空闲至少30秒(pingInterval的默认值+ pingTimeout的默认值)时,套接字才能重新连接,但是我得到的只是同时重新连接客户。