I am building what I thought was a very simple server-client. I have built a simple Node.js server. Below is the implementation:
const http = require('http');
const { Server } = require('socket.io');
// Create an HTTP server
const server = http.createServer();
// Create a new instance of Socket.io by passing the HTTP server
const io = new Server(server);
// Listen for incoming socket connections
io.on('connection', (socket) => {
console.log('A user connected');
// Listen for messages from the client
socket.on('message', (message) => {
console.log('Message received:', message);
// Broadcast the message to all connected clients
io.emit('message', message);
});
// Listen for disconnection
socket.on('disconnect', () => {
console.log('A user disconnected');
});
});
// Start the server and listen on port 3000
const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
console.log(`Server listening on http://192.168.0.191 port ${PORT}`);
});
I successfully validated this server by writing a Node.js client test script:
const io = require('socket.io-client');
// Replace 'http://localhost:3000' with the URL of your socket.io server
const socket = io('http://localhost:3000');
// Listen for 'connect' event
socket.on('connect', () => {
console.log('Connected to server');
// Read input from command line and send it to the server
process.stdin.on('data', (data) => {
const message = data.toString().trim();
socket.emit('message', message);
console.log("Next Message Sent:", message)
});
});
// Listen for 'message' event
socket.on('message', (message) => {
console.log('Received message from server:', message);
});
// Listen for 'disconnect' event
socket.on('disconnect', () => {
console.log('Disconnected from server');
});
The problem that I'm having is with the Android application. I'm receiving XHR polling errors. I'm not able to pinpoint the root cause. This is the implementation:
build.gradle.kts:
implementation("dev.icerock.moko:socket-io:0.4.0")
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<uses-feature android:name="android.software.leanback" android:required="true" />
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
<uses-feature
android:name="android.hardware.location.gps"
android:required="false" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<application
...
android:usesCleartextTraffic="true"
android:networkSecurityConfig="@xml/network_security_config"
android:banner="@drawable/logo">
...
The implementation of the network-security-config.xml file:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">192.168.0.191</domain>
</domain-config>
</network-security-config>
Finally, implementation relevant to the socket:
@Composable
private fun createMokoSocketIO() {
val coroutineScope = rememberCoroutineScope()
coroutineScope.launch(Dispatchers.IO) {
try {
val socket = Socket(
endpoint = "http://192.168.0.10:3000",
config = SocketOptions(
queryParams = mapOf("payload" to "MyPayload"),
transport = SocketOptions.Transport.DEFAULT
)
) {
on(SocketEvent.Connect) {
println("moko.socket: connect")
}
on(SocketEvent.Connecting) {
println("moko.socket: connecting")
}
on(SocketEvent.Disconnect) {
println("moko.socket: disconnect")
}
on(SocketEvent.Error) {
println("moko.socket: error $it")
}
on(SocketEvent.Reconnect) {
println("moko.socket: reconnect")
}
on(SocketEvent.ReconnectAttempt) {
println("moko.socket: reconnect attempt $it")
}
on(SocketEvent.Ping) {
println("moko.socket: ping")
}
on(SocketEvent.Pong) {
println("moko.socket: pong")
}
on("message") { data ->
println("moko.socket: message=[$data]")
//...
}
}
socket.connect()
socket.emit("message", "Hello, server!")
} catch (e: URISyntaxException) {
println("moko.socket: Error: ${e.message}")
return@launch
}
}
}
I need suggestions troubleshooting this issue. These are my logs:
moko.socket: error io.socket.engineio.client.EngineIOException: xhr poll error
moko.socket: error io.socket.client.SocketIOException: Connection error
I also tried to use a different 3rd party library, only to receive the same result:
implementation("io.socket:socket.io-client:1.0.0")
The server runs on my local machine, while the Android application is installed onto a mobile device. Both devices are on the same WIFI network. I even tried to connect using a tool such as NGROK, only to receive the same result.
Does anyone have any ideas? I hope all of this source code helps.
Thanks
This video assisted me in finding a solution.
Both the server and the client required modifications.
This is the full implementation of the server:
On the Android app, I imported a different library. As of the time of this post, this is the latest version of the library:
Finally, this is the full implementation, applicable to the socket: