简体   繁体   中英

Android Socket.IO implementation can't connect to Express server running Socket.IO - Wireshark shows an HTTP 400/ Bad Request?

I'm trying to connect an Android app using Native Socket.IO to an Express server. The server has a very simple job (currently) of taking incoming traffic on 4200 and sending it back out to other clients so they can display it - although right now I'm just debugging the server and this Android implementation, hoping for the beautiful text "client connected"

This is the server API

// Socket handling
io.on( 'connection', (socket) => {
    console.log('Client Connected');
  
    socket.on('temperature', (data) => {
      console.log('Engine Data:' + data);
      // For now, just spit data back to all other connected clients
      socket.broadcast.emit('temperature', {num: data});
    });
  
    socket.on('disconnect', ()=> {
      console.log('Client disconnected');
    });
});

Currently this works with a basic Node.JS client sending random numbers, so I know the server works:

    <script>
        var socket = io('http://localhost:4200');

        socket.on('connection',  (socket) => {
            console.log('Connection Success');
        });

        let temperature = 0;
        //Send stuff every 100ms
        setInterval(() => {
            let lastTemp = temperature < 90 ? temperature : 0;
            temperature = Math.floor(Math.random() * 5) + lastTemp;

            socket.emit('temperature', temperature);
        }, 50);
    </script>

However my Android app is having issues - the server doesn't log a connection like it does the browser client, and while it isn't throwing an exception on connection, the socket ID is just NULL and the state is "not connected" when debugging. I've been following different tutorials and trying solutions posted on StackOverflow, so I currently have a main activity utilizing a seek bar for dummy values that looks like this:

//! SocketIO stuff
import com.github.nkzawa.socketio.client.IO
import com.github.nkzawa.socketio.client.Socket


 class MainActivity : AppCompatActivity() {
    //! Instantiate socket for other functions that will utilize it - this will likely be part of its own class
    lateinit var mSocket: Socket

    //! Main Activity creation
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        setSupportActionBar(findViewById(R.id.toolbar))

        //! SeekBar for setting dummy input by user
        val seek: SeekBar = findViewById<SeekBar>(R.id.seekBar)
        seek.max = 100
        seek.progress = 50

        //! CurrentVal is our current dummy sensor value
        var currentVal: Int;

        //! Connect to web server
        try {
            //! Configure library options
            val options = IO.Options()
            options.reconnection = true
            options.forceNew = true
            //This address is the way you can connect to localhost with AVD(Android Virtual Device)
            mSocket = IO.socket("http://10.0.2.2:4200/", options) // emulator loopback address
        } catch (e: Exception) {
            e.printStackTrace()
            Log.d("Failure", "Failed to connect to server")
        }
        Log.d("Connected", "socket ID:${mSocket.id()}")
        mSocket.connect()
        seek.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
...
            override fun onStopTrackingTouch(seek: SeekBar) {
                //Progress stopped
                //get value from seek bar
                currentVal = seek.progress
                //Send the value via our socket
                mSocket.emit("temperature", currentVal)
            }
        })
    }

My Manifest includes the following based on feedback from other StackOverflow suggestions

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <application
        ...
        android:usesCleartextTraffic="true"
...

However the server doesn't reflect that a client is connected. When I look at Wireshark, I see that there is indeed a port 55735 that's trying to connect to the server running on 4200, however the server is responding with "400 Bad Request" and the JSON string value is "Unsupported protocol version"

2899    23.395504   127.0.0.1   127.0.0.1   HTTP/JSON   287 HTTP/1.1 400 Bad Request , JavaScript Object Notation (application/json)

This leads me to believe that there's some compatibility issue with the Socket.IO library I'm using and Socket.IO on the server. The tutorial I'm using is on the Socket.IO website... but it's also from 2015. Should I be following a different way to use Socket.IO on Android?

I seem to have figured out the issue - the socket.io library for Android was not compatible with the latest 3.1.1 in NPM

This was mainly shown by watching the data in Wireshark - I had communication between the ports, however the response - mainly the JSON in the response - indicated an incorrect protocol version

In short the dependency in my build.gradle file for the app, shown in the original tutorial from Socket.IO from 2015 is WAY out of date

implementation 'com.github.nkzawa:socket.io-client:0.6.0' 
//OUT OF DATE

This implementation from Joyce Hong was closer...

implementation ('io.socket:socket.io-client:1.0.0') {
        exclude group: 'org.json', module: 'json'
    }
//Still nope, but that was a clue

However, the implementation that's compatible with my 3.1.1 Socket.IO library in NPM is

implementation ('io.socket:socket.io-client:2.0.0') {
        exclude group: 'org.json', module: 'json'
    }
//YES

If anyone else is running into this issue where there's traffic between ports, but neither is registering a connection, check your versions

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