简体   繁体   中英

Sending data from express server to react-native client using socket.io

I am trying to send data from my express server to react-native client using socket.io to implement some real time functionality. But I have been facing some issues which I am not able to resolve after going through multiple articles / stackoverflow posts.

I am using ngrok to connect my react-native app via expo with the server. The other functionalities in the app are working correctly but the connection between the sockets on client and server side is not correctly established.

When I use the IP address as the URL (" http://192.ip.address.:8000 ") to connect the sockets on server and the client, I can see that the socket.connected is true in all the react-native screens where I am importing the socket client. But the message is not received.

Also, is there a better way to share the same socket instance / connection across multiple files both on the server / client side?

Server side code

Setting up socket.io in index.js

const app = express();
const expressRouter = require("./routes");
const socketio = require("socket.io");

app.set("view engine", "ejs");
app.set("views", "./views");
app.use(express.urlencoded());
app.use("/", expressRouter);

const server = app.listen(port, function (err) {
  if (err) {
    console.log(`Failed to run the server: ${err}`);
    return;
  }
  console.log(`Server running successfully on port: ${port}`);
});

const io = socketio(server);
app.set("io", io);

Emitting message via one of the controllers (/controllers/homeController.js) handles --> /home

module.exports.getHome = function (request, response) {
  let io = request.app.get("io");

  io.on("connection", function (socket) {
    console.log("connected io");
    io.sockets.emit("some-channel", "some other new message text");
  });
  return response.render("dashboard");
};

React-Native Code

Setting up socket client to use in all the screens (src/utils/socket.js)

import Constants from "./Constants";
import io from "socket.io-client";
export const socket = io(Constants.getNgrokUrl());

Using socket.io client in some other screen (src/screens/homeScreen.js)

import { socket } from "../utils/socket";

const HomeScreen = ({ navigation }) => {
    const [socketData, setSocketData] = useState(""); 
    console.log("socket connection", socket.connected, "on home screen");

    socket.on("some-channel", function (data) {
      console.log("new data received", data);
      setSocketData(data);
    });

  return (
    <View>
       <Text>{socketData}</Text>
   </View>
);
};

You can create a singleton class to handle this. In my app, I using as following

import io from 'socket.io-client';
import { SOCKET_SERVER } from './Constant';
import async from 'async';

export default class SocketInstance {
    static instance = null;
    static socketConn = null;
    static online = false;

    static getInstance(){
        if(SocketInstance.instance === null){
            SocketInstance.instance = new SocketInstance();
            SocketInstance.getSocket();
        }
        return this.instance;
    }

    static getSocket(){
        if(SocketInstance.socketConn === null){
            SocketInstance.socketConn = io.connect(SOCKET_SERVER,{ forceNew: true });
            const handshake = {
                    username: results.username,
                    client: results.client,
                    database:[{ last_updated_time: new Date(), table_name:'TODO-later' }]
                };
                SocketInstance.socketConn.on('connect',()=>{
                    console.warn('socket running in shared instance');
                    SocketInstance.socketConn.emit('*',handshake);
                    SocketInstance.online = true;
                });
                SocketInstance.socketConn.on('disconnect',()=>{
                    console.warn('--socket disconnected in shared instance--');
                    SocketInstance.online = false;
                });
        }
        return this.socketConn;
    }

    send(message, data){
        if(SocketInstance.socketConn !== null){
            SocketInstance.socketConn.emit(message,data);
        }else{
            SocketInstance.getSocket();
        }
    }

    listen(message,func){
        if(SocketInstance.socketConn !== null){
            SocketInstance.socketConn.on(message,(data)=>{
                func(data);
            });
        }else{
            SocketInstance.getSocket();
        }
    }

    isOnline(){
        if(SocketInstance.socketConn !== null){
            if(SocketInstance.socketConn.connected === false){
                SocketInstance.getSocket();
            }
            return SocketInstance.socketConn.connected;
        }else{
            SocketInstance.getSocket();
            return false;
        }
    }
}

In your screens, you can do as following

const socket = SocketInstance.getInstance();
socket.send('*',{ data });
socket.listen('data',(res)=>{
    console.warn(res);
});

BUT... Remember to call the following line in your index.js or App.js file. I mean when the app loads

SocketInstance.getInstance();

The firewall connection of the server side must be turned off before trying to connect the client to it. This is because the client can only connect to a port of the server if the firewall is off.

For the second part of the question, you can do multiple connections by hosting the application on a hosting platform like Heroku. However, if you are on the development stage, this is not advisable as this is a more complicated process to get through. Hence, ngrok is more advisable at this stage. If you are using an android emulator with react native, then a normal http request link without ngrok will also work.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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