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(客户端)连接的主要内容,如果未能解决你的问题,请参考以下文章

带有 iOS 的 Socket.io 未在移动客户端上连接

在nodeJs中将pm2与socket io集成[关闭]

MongoError:未在 db 上授权执行命令?与 socket.io 连接时

在Socket.IO 1.0中将消息发送到特定ID

在 ExpressJS 中将 socket.io 实现为子模块的最佳方法是啥?

Socket.io、Node.js:如何在 javascript.js 中将 javascript 变量传递给 mysql 查询?