Подтвердить что ты не робот

Приложение Android Подключение к серверу Node.js с помощью Socket.io

У меня возникли проблемы с подключением моего приложения для Android к серверу чата socket.io. Я использую socket.io-java-клиент, созданный Gottox, который можно найти здесь: https://github.com/Gottox/socket.io-java-client

Сервер работает локально через порт 7000. Я использую эмулятор android, поэтому я использую 10.0.2.2:7000 для доступа к серверу.

Любая помощь будет оценена по достоинству, у меня нет большого опыта работы с SSL. Если я найду рабочее решение, я также опубликую его.

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

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

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

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

Код ошибки

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
4b9b3361

Ответ 1

Я действительно решил проблему. Я использовал локальный IP-адрес компьютера http://192.168.0.xxx:7000, и приложение смогло подключиться к серверу чата из эмулятора. Я не знаю, почему это работает, но это может помочь кому-то в будущем:)

Update:

Вот как я закончил структурирование проекта. Я создал одноэлементный класс для обработки сокетов на Android-стороне (вы также можете сделать это как услугу). При получении сообщения одноэлементный класс передает намерение остальной части приложения. Затем намерение принимается широковещательным приемником в соответствующей деятельности.

Android Side (singleton):

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 (активность):

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

Сторона сервера:

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

    });
});

Ответ 2

Я знаю, что это действительно не ответы на сообщения OP, но для тех, кто может быть заинтересован, это учебник, который я сделал, чтобы сообщить об этом Android с сервером Node.js - без дополнительной библиотеки -:

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

Это предвкушение того, как это выглядит в конце:

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

Ответ 3

Эмуляторная сеть отличается от вашего компьютера, как я слышал. Поэтому, если вы можете поменять это, попробуйте это на реальном телефоне, который подключен к той же сети, что и ваш компьютер.

Вероятно, вы не сможете ping 10.0.2.2 от вашего эмулятора или наоборот от вашего компьютера до эмулятора.

Ответ 4

Puma уже ответила, как вы можете реализовать соединение сокета с помощью SocketIO. У этого нет ничего нового, чтобы внести свой вклад. Тем не менее, это попытка помочь новичкам-новичкам, а также представить реализацию java-библиотеки Socket.io.

Socket.IO имеет собственную реализацию java на Github, которую вы можете использовать для создания приложения сокета для Android/Java.

сторона Android:

Включите это в свою сборку gradle

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

Предоставить разрешение в вашем приложении:

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

Код Android: Структура кода аналогична структуре кода Node. сообщение в 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 сторона

Создайте обычные сокеты, используя socket.io