So, I would keep this answer as comprehensive as possible. I will share a small react-native application I build to help understand what exactly we need to do.
This answer is a working extension to @ßãlãjî 's answer.
Libraries we need:
// In App.js
import {createAppContainer} from 'react-navigation';
import {createStackNavigator} from 'react-navigation-stack';
import ClientScreen from './src/screens/ClientScreen';
import ServerScreen from './src/screens/ServerScreen';
const navigator = createStackNavigator({
Server: ServerScreen,
Client: ClientScreen
});
export default createAppContainer(navigator);
// In ClientScreen.js
import React, {useState, useEffect} from 'react';
import {View, Text, Button, FlatList, TextInput} from 'react-native';
import { NetworkInfo } from 'react-native-network-info';
var net = require('react-native-tcp');
const createClient = (ip, chats, setChats) => {
const client = net.createConnection(6666,ip, () => {
console.log('opened client on ' + JSON.stringify(client.address()));
// client.write('Hello, server! Love, Client.');
});
client.on('data', (data) => {
setChats([...chats, {id:chats.length+1, msg:data}]);
// console.log('Client Received: ' + data);
// client.destroy(); // kill client after server's response
// this.server.close();
});
client.on('error', (error) => {
console.log('client error ' + error);
});
client.on('close', () => {
console.log('client close');
});
return client;
};
const ClientScreen = ({navigation}) => {
const [client, setClient] = useState(null);
const [chats, setChats] = useState([]);
useEffect(async () => {
let ip = await NetworkInfo.getIPV4Address(); //await NetworkInfo.getGatewayIPAddress();
setClient(createClient(ip));
return () => {};
}, []);
return <View>
<Text>Client Screen</Text>
<Button title="Stop Client" onPress={() => {
if(client){
client.destroy();
setClient(null);
}
}}/>
{client ? <Text>Client is on</Text>: null}
<FlatList
data={chats}
renderItem={({item}) =>{
return <Text style={{margin:10, fontSize:20}}>{item.msg}</Text>;
}}
keyExtractor={item => item.id}
/>
<TextInput placeholder="Type a message" placeholderTextColor="black" style={{margin:10, borderWidth:2, color:'black'}} onSubmitEditing={({nativeEvent: {text}}) => {
if(client){
client.write(JSON.stringify({msg:text, id:1}));
}
}}/>
</View>;
};
export default ClientScreen;
// In ServerScreen.js
import React, {useState} from 'react';
import {View, Text, Button, StyleSheet, FlatList} from 'react-native';
import { NetworkInfo } from 'react-native-network-info';
var net = require('react-native-tcp');
const createServer = (chats, setChats) => {
const server = net.createServer((socket) => {
console.log('server connected on ' + socket.address().address);
socket.on('data', (data) => {
let response = JSON.parse(data);
setChats([...chats, {id:chats.length+1, msg:response.msg}]);
// console.log('Server Received: ' + data);
// socket.write('Echo server\r\n');
});
socket.on('error', (error) => {
console.log('error ' + error);
});
socket.on('close', (error) => {
console.log('server client closed ' + (error ? error : ''));
});
}).listen(6666, () => {
console.log('opened server on ' + JSON.stringify(server.address()));
});
server.on('error', (error) => {
console.log('error ' + error);
});
server.on('close', () => {
console.log('server close');
});
return server;
};
const ServerScreen = ({navigation}) => {
const [server, setServer] = useState(null);
const [chats, setChats] = useState([]);
const [ip, setIp] = useState('');
return <View>
{ip.length > 0? <Text>Server Screen: {ip}</Text>: <Text>Server Screen</Text>}
<Button title="Start Server" onPress={async () => {
if(!server)
setServer(createServer(chats, setChats));
try{
let temp_ip = await NetworkInfo.getIPV4Address();
setIp(temp_ip);
}catch(e){
console.log(e.message);
}
}}/>
<Button title="Stop Server" onPress={() => {
if(server){
server.close();
setServer(null);
}
}}/>
<Button title="Go to Client Screen" onPress={() => navigation.navigate('Client')}/>
{server ? <Text>Server is on</Text>: null}
<FlatList
data={chats}
renderItem={({item}) =>{
return <Text style={{margin:10, fontSize:20}}>{item.msg}</Text>;
}}
keyExtractor={item => item.id}
/>
</View>;
};
const styles = StyleSheet.create({});
export default ServerScreen;
Firstly, how to run this application.
- Build and Install this into a physical device or Emulator.
- First, go to ServerScreen.
- In the ServerScreen press on
Start Server
button. You will be able to see an IP address pop in the screen.
- Now navigate to ClientScreen. The Client socket gets automatically invoked once you navigate to this Screen. Here you can see a button and a text input field. Type in some message in the field and submit from the keyboard. Press the
Stop Client
button to avoid any errors.
- Go back to the ServerScreen you will be able to see the message that you typed in the ClientScreen.
Now, this is a minimal example of how to communicate between 2 devices through local network. But as you might be wondering, this app only lets us communicate between 2 screens right?
To be honest, thats true, we are only able to communicate between 2 screens so far using this application, but, the underlying mechanism we used to make it work is exactly same as what we would do in case of communication between 2 devices.
So, how to do it for different devices.
Lets say we have 2 device, namely A and B. We want to establish a connection between both of these device. Firstly, we will turn on the wifi hotspot of A, and will connect B to that wifi.
Now, on device A, we will go to the ServerScreen and start the server. On device B, go to ClientScreen and you will see "client is on" info appear, but if you type in some message in the textfield and submit, you wont be seeing any message appear on Device A, this is because to make it work, we need to change a little bit on the ClientScreen.js
component file.
Change from =>
useEffect(async () => {
let ip = await NetworkInfo.getIPV4Address(); //await NetworkInfo.getGatewayIPAddress();
setClient(createClient(ip));
return () => {};
}, []);
to =>
useEffect(async () => {
let ip = await NetworkInfo.getGatewayIPAddress();
setClient(createClient(ip));
return () => {};
}, []);
What this does is, the IP that we want, to connect our device B to device A, is the IP of the Gateway of device B (Remember, we connected B to the hotspot of A).
That's it.
Now simply build again and follow the steps previously mentioned. Once you type in a message and submit it over the ClientScreen on B, you will be able to see it on ServerScreen of A.
Hope this helps anyone who is struggling with establishing a local socket connection between devices.
Note that, you can sure have multiple clients with a single server with some little behaviourial change on ServerScreen and this same codebase.
PS. I will make sure that I keep a check on this answer frequently so that any issue you face, you can comment and I can get back to you ASAP.
Edit: If you want to sent messages to the client system from the main system (hotspot), then you can follow this answer https://mcmap.net/q/1172644/-how-to-send-data-from-device-that-hotspot-on-to-other-device-that-connected-with-hotspot-in-react-native.