Socket io 未在 HTTPS 中将 nodejs 与 android(客户端)连接
Posted
技术标签:
【中文标题】Socket io 未在 HTTPS 中将 nodejs 与 android(客户端)连接【英文标题】:Socket io is not connect nodejs with android (Client) in HTTPS 【发布时间】:2021-10-05 00:05:48 【问题描述】:使用 NodeJS 添加的自签名证书 (HTTPS) 将文本表单 NodeJS Socket io 简单地传递给 android 客户端,我得到了错误
添加:android:usesCleartextTraffic="true",互联网权限
错误:I/IO 连接错误:com.github.nkzawa.engineio.client.EngineIOException:xhr 轮询错误
我试过Android: socket.io io.socket.engineio.client.EngineIOException: XHR poll error
在那个答案中 io.set('transsports', ['websocket']);想在nodejs服务器中添加,但是我在我的服务器中添加了错误
Error: TypeError: Cannot read property 'transports' of undefined
帮我解决这个问题
App.js
const express = require('express')
const https = require('https')
const fs = require('fs')
const path = require('path')
const app = express()
var bodyParser = require('body-parser');
var io = require('socket.io')(https);
io.on('connection',function(socket)
console.log('one user connected '+socket.id);
socket.emit('CHAT',"message":"hy");
socket.on('disconnect',function()
console.log('one user disconnected '+socket.id);
);
)
app.use(bodyParser.json());
app.use(bodyParser.urlencoded(extended:true));
con.connect(function(err)
if (err) throw err
console.log('You are now connected with mysql database...')
);
app.use('/',(req,res,next) =>
res.send('Hello from SSL server!!!')
)
const sslServer = https.createServer(
key: fs.readFileSync(path.join(__dirname,'cert','key.pem')),
cert: fs.readFileSync(path.join(__dirname,'cert','cert.pem')),
,
app
)
sslServer.listen(3000, () => console.log("Secure Server on port 3000"))
MainActivity.java
public class Main2Activity extends AppCompatActivity
public Button button1;
public TextView text1,text2,text3,text4;
public EditText edit1;
public String message;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
button1 = findViewById(R.id.button);
text1 = findViewById(R.id.textview);
edit1 = findViewById(R.id.edit);
// mSocket.connect();
text1.setText("");
final String uri = "https://192.168.43.182:3000";
try
// Load CAs from an InputStream.
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
Certificate certificate = certificateFactory.generateCertificate(
getResources().openRawResource(R.raw.cert)); // from file server.crt
// Create a KeyStore containing the trusted CAs.
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", certificate);
// Create a TrustManager that trusts the CAs in KeyStore.
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
// Create an SSLContext that uses the TrustManager.
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
Log.i("uri", "sslContext created");
IO.setDefaultSSLContext(sslContext);
IO.Options options = new IO.Options();
options.secure = true;
options.path = "/web-live";
options.reconnection = true;
options.upgrade = true;
options.sslContext = sslContext;
URL url = new URL(uri);
final HttpsURLConnection httpsURLConnection = (HttpsURLConnection) url.openConnection();
httpsURLConnection.setSSLSocketFactory(sslContext.getSocketFactory());
httpsURLConnection.setHostnameVerifier(new HostnameVerifier()
@Override
public boolean verify(String hostname, SSLSession session)
Log.i("HostnameVerifier", "Approving certificate for " + hostname);
return true; // Do nothing.
);
new Thread(new Runnable()
@Override
public void run()
try
BufferedReader in = new BufferedReader(new InputStreamReader(
httpsURLConnection.getInputStream()));
Log.i("httpsURLConnection", "url connected");
String line; //FIXME: readLine kicks in socket.io at least on gingerbread!?
while((line = in.readLine()) != null)
Log.i("httpsURLConnection", line);
in.close();
catch (IOException e)
).start();
Socket socket = IO.socket(uri, options);
socket.on(Socket.EVENT_CONNECT_ERROR, new Emitter.Listener()
@Override
public void call(Object... args)
for(Object o : args)
Log.i("IO " + Socket.EVENT_CONNECT_ERROR, o.toString());
).on(Socket.EVENT_CONNECT_TIMEOUT, new Emitter.Listener()
@Override
public void call(Object... args)
Log.i("IO", Socket.EVENT_CONNECT_TIMEOUT);
).on(Socket.EVENT_CONNECT, new Emitter.Listener()
@Override
public void call(Object... args)
Log.i("IO", Socket.EVENT_CONNECT);
).on("secure_data", new Emitter.Listener()
@Override
public void call(Object... args)
Log.i("IO secure_data", args[0].toString());
);
socket.connect();
catch (Exception e)
e.printStackTrace();
密钥是由 openssl 生成的,它在使用 RestApi 时可以正常工作。我只有连接问题帮我解决这个问题
【问题讨论】:
【参考方案1】:尝试检查以下可能在客户端和服务器之间
检查您在客户端使用的版本 socket.io 是否支持在服务器(Nodejs)端使用的版本 在成功连接或发送请求之前,有时会从客户端生成多个请求或多个实例 待处理,因此请尝试在创建新实例之前正确断开连接。 尝试更新从轮询到 websocket 的传输请检查下面的代码行可能对你有帮助
public void initSocket()
try
SSLContext mySSLContext = SSLContext.getInstance("TLS");
mySSLContext.init(null, trustAllCerts, new SecureRandom());
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.hostnameVerifier(myHostnameVerifier)
.sslSocketFactory(mySSLContext.getSocketFactory(), (X509TrustManager) trustAllCerts[0])
.build();
IO.setDefaultOkHttpWebSocketFactory(okHttpClient);
IO.setDefaultOkHttpCallFactory(okHttpClient);
IO.Options opts = new IO.Options();
opts.callFactory = okHttpClient;
opts.webSocketFactory = okHttpClient;
opts.timeout = 60 * 1000;
opts.forceNew = false;
opts.secure = true;
opts.reconnection = true;
mSocket = IO.socket(socketUrl, opts);
mSocket.connect();
mSocket.on(Socket.EVENT_CONNECT, new Emitter.Listener()
@Override
public void call(Object... args)
Log.e(TAG,"socket connected");
).on(Socket.EVENT_DISCONNECT, new Emitter.Listener()
@Override
public void call(Object... args)
Log.e(TAG,"socket disconnected");
).on(Socket.EVENT_ERROR, new Emitter.Listener()
@Override
public void call(Object... args)
Log.e(TAG,"socket error");
).on(Socket.EVENT_CONNECT_TIMEOUT, new Emitter.Listener()
@Override
public void call(Object... args)
Log.e(TAG,"socket connection timeout");
);
catch (URISyntaxException e)
throw new RuntimeException(e);
catch (NoSuchAlgorithmException e)
e.printStackTrace();
catch (KeyManagementException e)
e.printStackTrace();
catch (IllegalStateException e)
e.printStackTrace();
catch (Exception e)
e.printStackTrace();
TrustManager[] trustAllCerts = new TrustManager[]new X509TrustManager()
public java.security.cert.X509Certificate[] getAcceptedIssuers()
return new java.security.cert.X509Certificate[];
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException
;
HostnameVerifier myHostnameVerifier = new HostnameVerifier()
@Override
public boolean verify(String hostname, SSLSession session)
return true;
;
【讨论】:
我的 nodejs 版本 "socket.io": "^2.3.0" 和 android - "io.socket:socket.io-client:2.0.0" 请阅读详细信息github.com/socketio/socket.io-client-java以检查客户端服务器中的版本不匹配,也请在初始化套接字对象时先断开连接并在您的流程中连接,然后检查isConnected是否已连接,然后向服务器请求或处理否则会报错以上是关于Socket io 未在 HTTPS 中将 nodejs 与 android(客户端)连接的主要内容,如果未能解决你的问题,请参考以下文章
MongoError:未在 db 上授权执行命令?与 socket.io 连接时
在 ExpressJS 中将 socket.io 实现为子模块的最佳方法是啥?
Socket.io、Node.js:如何在 javascript.js 中将 javascript 变量传递给 mysql 查询?