简体   繁体   English

Android App使用Socket.io连接到Node.js服务器

[英]Android App Connecting to Node.js server using Socket.io

I'm having trouble getting my Android app to connect to a socket.io chat server. 我无法让我的Android应用程序连接到socket.io聊天服务器。 I'm using socket.io-java-client created by Gottox which can be found here: https://github.com/Gottox/socket.io-java-client 我正在使用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. 任何帮助将不胜感激,我对SSL没有太多经验。 If I find a working solution I'll also post it. 如果我找到一个有效的解决方案,我也会发布它。

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 的package.json

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

Android: SendMessageActivity Android: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 Android权限

<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.access$600(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

I actually solved the problem. 我实际上解决了这个问题。 I used my PC's local IP http://192.168.0.xxx:7000 and the app was able to connect to the chat server from the emulator. 我使用了我的PC的本地IP http://192.168.0.xxx:7000 ,该应用程序能够从模拟器连接到聊天服务器。 I don't know why this works, but it might help out someone in the future :) 我不知道为什么会这样,但它可能会帮助将来的某个人:)

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). 我创建了一个单例类来处理Android端的套接字连接(你也可以将其作为服务来实现)。 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 Side (singleton): Android Side(单身):

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): Android Side(活动):

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});

    });
});

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的帖子的真正答案,但是对于那些可能感兴趣的人来说,这是我用来与Node.js服务器通信你的Android的教程 - 没有任何额外的库 - :

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();

Puma has already answered on how you can implement a socket connection using SocketIO. Puma已经回答了如何使用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. 然而,它是一个尝试帮助新手,同时也介绍了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: Android方面:

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 Permission in your app: 在您的应用中提供权限

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

Android Code: The structure of code is similar to how you would code in Node. Android代码:代码结构类似于您在Node中编码的方式。 The message in socket.on is similar to node's socket.on('message', ...) socket.on中的消息类似于node的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){ } 

Node.js side Node.js方面

Create normal sockets using socket.io 使用socket.io创建普通套接字

You're emulator network is different from your PC's as I have heard. 正如我所听到的,你的模拟器网络与你的PC不同。 So if you could by change try this on an actual phone that is connected to the same network as your PC. 因此,如果您可以通过更改在与PC连接到同一网络的实际手机上尝试此操作。

You probably wont be able to ping 10.0.2.2 from your emulator or the other way around from your pc to emulator. 你可能无法从你的模拟器ping 10.0.2.2或从你的电脑到模拟器的另一种方式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM