Android 应用程序使用 Socket.io 连接到 Node.js 服务器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25223189/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 09:14:43  来源:igfitidea点击:

Android App Connecting to Node.js server using Socket.io

androidnode.jssocketssslsocket.io

提问by Puma

I'm having trouble getting my Android app to connect to a socket.io chat server. I'm using socket.io-java-client created by Gottox which can be found here: https://github.com/Gottox/socket.io-java-client

我在让我的 Android 应用程序连接到 socket.io 聊天服务器时遇到问题。我正在使用由 Gottox 创建的 socket.io-java-client,可以在这里找到:https: //github.com/Gottox/socket.io-java-client

The server runs locally over port 7000. I'm using the android emulator, so I'm using 10.0.2.2:7000 to access the server.

服务器通过端口 7000 在本地运行。我使用的是 android 模拟器,所以我使用 10.0.2.2:7000 来访问服务器。

Any help would be appreciated, I don't have much experience at all with SSL. If I find a working solution I'll also post it.

任何帮助将不胜感激,我对 SSL 没有太多经验。如果我找到了一个可行的解决方案,我也会发布它。

Node.js Server

Node.js 服务器

var express = require('express');
var app = express();
var server = require('http').createServer(app).listen(7000);
var io = require('socket.io').listen(server);
io.sockets.on('connection', function(client){
    client.on('message', function(err, msg){
        client.broadcast.emit('message', msg);
    });
 });

package.json

包.json

{
  "name": "simplechat",
  "version": "0.0.1",
  "main": "app.js",
  "dependencies": {
    "express" : "~4.0.0",
    "socket.io" : "~0.9.13"
  }
}

Android: SendMessageActivity

安卓:SendMessageActivity

public class SendMessageActivity extends Activity {

    private static final String SERVER_ADDRESS = "https://10.0.2.2:7000";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_send_message);

        System.out.println("Sever: " + SERVER_ADDRESS);

        try {
            SocketIO socket = new SocketIO(new URL(SERVER_ADDRESS), new IOCallback() {
                @Override
                public void onDisconnect() {
                    System.out.println("disconnected");
                }

                @Override
                public void onConnect() {
                    System.out.println("connected");
                }

                @Override
                public void onMessage(String s, IOAcknowledge ioAcknowledge) {
                }

                @Override
                public void onMessage(JSONObject jsonObject, IOAcknowledge ioAcknowledge) {
                }

                @Override
                public void on(String event, IOAcknowledge ioAcknowledge, Object... objects) {
                }

                @Override
                public void onError(SocketIOException e) {
                    e.printStackTrace();
                }
            });

        } catch (MalformedURLException ex) {
            ex.printStackTrace();
        }
    }

Android Permissions

安卓权限

<uses-permission
    android:name="android.permission.INTERNET">
</uses-permission>

Error Code

错误代码

08-09 16:07:28.224    8411-8441/com.example.puma.chatexample W/System.err﹕ io.socket.SocketIOException: Error while handshaking
08-09 16:07:28.225    8411-8441/com.example.puma.chatexample W/System.err﹕ at io.socket.IOConnection.handshake(IOConnection.java:322)
08-09 16:07:28.225    8411-8441/com.example.puma.chatexample W/System.err﹕ at io.socket.IOConnection.access0(IOConnection.java:39)
08-09 16:07:28.225    8411-8441/com.example.puma.chatexample W/System.err﹕ at io.socket.IOConnection$ConnectThread.run(IOConnection.java:199)
08-09 16:07:28.226    8411-8441/com.example.puma.chatexample W/System.err﹕ Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'javax.net.ssl.SSLSocketFactory javax.net.ssl.SSLContext.getSocketFactory()' on a null object reference
08-09 16:07:28.226    8411-8441/com.example.puma.chatexample W/System.err﹕ at io.socket.IOConnection.handshake(IOConnection.java:302)
08-09 16:07:28.227    8411-8441/com.example.puma.chatexample W/System.err﹕ ... 2 more

回答by Puma

I actually solved the problem. I used my PC's local IP http://192.168.0.xxx:7000and the app was able to connect to the chat server from the emulator. I don't know why this works, but it might help out someone in the future :)

我实际上解决了这个问题。我使用了我 PC 的本地 IP http://192.168.0.xxx:7000并且该应用程序能够从模拟器连接到聊天服务器。我不知道这为什么有效,但它可能会在将来对某人有所帮助:)

Update:

更新:

This is how I ended up structuring the project. I created a singleton class to handle socket connections Android side (you could also do it as a service). When receiving a message, the singleton class broadcasts an intent to the rest of the app. The intent is then picked up by a broadcast receiver in the relevant activity.

这就是我最终构建项目的方式。我创建了一个单例类来处理 Android 端的套接字连接(您也可以将其作为服务来实现)。接收消息时,单例类向应用程序的其余部分广播一个意图。然后意图被相关活动中的广播接收器接收。

Android Side (singleton):

Android 端(单例):

public class SocketSingleton {

    private static SocketSingleton instance;
    private static final String SERVER_ADDRESS = "http://1.2.3.4:1234";
    private SocketIO socket;
    private Context context;

    public static SocketSingleton get(Context context){
        if(instance == null){
            instance = getSync(context);
        }
        instance.context = context;
        return instance;
    }

    public static synchronized SocketSingleton getSync(Context context){
        if (instance == null) {
            instance = new SocketSingleton(context);
        }
        return instance;
    }

    public SocketIO getSocket(){
        return this.socket;
    }

    private SocketSingleton(Context context){
        this.context = context;
        this.socket = getChatServerSocket();
        this.friends = new ArrayList<Friend>();
    }

    private SocketIO getChatServerSocket(){
        try {
            SocketIO socket = new SocketIO(new URL(SERVER_ADDRESS), new IOCallback() {
                @Override
                public void onDisconnect() {
                    System.out.println("disconnected");
                }

                @Override
                public void onConnect() {
                    System.out.println("connected");
                }

                @Override
                public void on(String event, IOAcknowledge ioAcknowledge, Object... objects) {
                    if (event.equals("chatMessage")) {
                        JSONObject json = (JSONObject) objects[0];
                        ChatMessage chatMessage = new ChatMessage(json);

                        Intent intent = new Intent();
                        intent.setAction("newChatMessage");
                        intent.putExtra("chatMessage", chatMessage);
                        context.sendBroadcast(intent);
                    }
                }
                @Override
                public void onError(SocketIOException e) {
                    e.printStackTrace();
                }
            });
            return socket;
        } catch (MalformedURLException ex) {
            ex.printStackTrace();
        }
        return null;
    }
}

Android Side (activity):

安卓端(活动):

public class ChatActivity extends Activity {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_chat);
    IntentFilter newChatMessageFilter = new IntentFilter("newChatMessage");
    this.registerReceiver(new MessageReceiver(), newChatMessageFilter);

    ...

    public class MessageReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent){
            final ChatMessage chatMessage =(ChatMessage) intent.getExtras().get("chatMessage");
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    mAdapter.add(chatMessage);
                    mAdapter.notifyDataSetChanged();
                }
            });
        }
    }
} 

Server Side:

服务器端:

var express = require('express');
var app = express();
var server = require('http').createServer(app).listen(1234);
var io = require('socket.io').listen(server);

io.sockets.on('connection', function(client){

    console.log("client connected: " + client.id);

    client.on("sendTo", function(chatMessage){
        console.log("Message From: " + chatMessage.fromName);
        console.log("Message To: " + chatMessage.toName);


        io.sockets.socket(chatMessage.toClientID).emit("chatMessage", {"fromName" : chatMessage.fromName,
                                                                    "toName" : chatMessage.toName,
                                                                    "toClientID" : chatMessage.toClientID,
                                                                    "msg" : chatMessage.msg});

    });
});

回答by Omar Aflak

I know this not really answers to the OP's posts, but for those who may be interested, this is a tutorial I made to make communicate your Android with a Node.js server -without any additional library- :

我知道这并不是对 OP 帖子的真正答案,但对于那些可能感兴趣的人,这是我制作的一个教程,旨在让您的 Android 与 Node.js 服务器进行通信 -无需任何额外的库- :

https://causeyourestuck.io/2016/04/27/node-js-android-tcpip/

https://causeyourestuck.io/2016/04/27/node-js-android-tcpip/

This is a foretaste of how it looks like at the end:

这是最后的样子:

Client socket = new Client("192.168.0.8", 1234);
socket.setOnEventOccurred(new Client.OnEventOccurred() {
    @Override
    public void onMessage(String message) {
    }

    @Override
    public void onConnected(Socket socket) {
        socket.send("Hello World!");
        socket.disconnect();
    }

    @Override
    public void onDisconnected(Socket socket, String message) {
    }
});

socket.connect();

回答by adityah

Puma has already answered on how you can implement a socket connection using SocketIO. This has nothing new to contribute. Yet, it is an attempt to help fellow newbies, as also introduce the implementation of Socket.io's java library.

Puma 已经回答了如何使用 SocketIO 实现套接字连接。这没有什么新的贡献。然而,它是一种帮助新手的尝试,同时也介绍了 Socket.io 的 java 库的实现。

Socket.IO has its own java implementation on Github, which you can follow along to create a socket application for Android/Java.

Socket.IO 在Github上有自己的 java 实现,您可以按照它为 Android/Java 创建一个套接字应用程序。

Android side:

安卓端:

Include this in your build gradle

将此包含在您的构建gradle 中

compile ('io.socket:socket.io-client:0.8.3') {
    // excluding org.json which is provided by Android
    exclude group: 'org.json', module: 'json'
}

Provide Permissionin your app:

在您的应用中提供权限

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.INTERNET" />

Android Code:The structure of code is similar to how you would code in Node. The messagein socket.on is similar to node's socket.on('message', ...)

Android 代码:代码结构类似于您在 Node.js 中编写代码的方式。socket.on 中的消息类似于节点的 socket.on('message', ...)

import io.socket.client.Socket;
import io.socket.client.IO;
import io.socket.emitter.Emitter;

final Socket socket;
try{
socket = IO.socket("http://192.168.1.1:8080");

socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {

    @Override
    public void call(Object... args) {
        socket.emit("message", "hi");
        socket.disconnect();
    }

}).on("message", new Emitter.Listener() {
        //message is the keyword for communication exchanges
    @Override
    public void call(Object... args) {
        socket.emit("message", "hi");
    }

}).on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {

    @Override
    public void call(Object... args) {}

});
    socket.connect();

}
catch(Exception e){

}
import io.socket.client.Socket;
import io.socket.client.IO;
import io.socket.emitter.Emitter;

final Socket socket;
try{
socket = IO.socket("http://192.168.1.1:8080");

socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {

    @Override
    public void call(Object... args) {
        socket.emit("message", "hi");
        socket.disconnect();
    }

}).on("message", new Emitter.Listener() {
        //message is the keyword for communication exchanges
    @Override
    public void call(Object... args) {
        socket.emit("message", "hi");
    }

}).on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {

    @Override
    public void call(Object... args) {}

});
    socket.connect();

}
catch(Exception e){

}

Node.js side

Node.js 端

Create normal sockets using socket.io

使用 socket.io 创建普通套接字

回答by someguy234

You're emulator network is different from your PC's as I have heard. So if you could by change try this on an actual phone that is connected to the same network as your PC.

据我所知,您的模拟器网络与您的 PC 不同。因此,如果您可以更改,请在与 PC 连接到同一网络的实际手机上尝试此操作。

You probably wont be able to ping 10.0.2.2from your emulator or the other way around from your pc to emulator.

您可能无法ping 10.0.2.2从您的模拟器或从您的 PC 到模拟器的其他方式。