Vamos a crear una aplicación React Native que actuará como cliente Websockets y será capaz de comunicarse con un servidor remoto. WebSockets es un protocolo de comunicación web popular, simple y robusto que permite la comunicación en tiempo real entre cliente y servidor.
Hardware
- Dispositivo Android
- Ordenador para programar
- Un cable USB para conectar el dispositivo Android al PC
Configuración del proyecto React Native
Para comunicarnos a través de Websocket, vamos a utilizar la librería Websocket, react-use-websocket
npm install --save react-use-websocket
Uso de la biblioteca
De la biblioteca, importamos los objetos y funciones que nos interesan
import useWebSocket, { ReadyState } from 'react-use-websocket';
- ReadyState estado de la conexión con el servidor
- useWebScoket se utiliza para inicializar una conexión websockets
A continuación, creamos un componente funcional con los estados deseados
const [ipAddress, setIpAddress] = useState('');
const [ipServer, setIpServer] = useState('ws://192.168.1.52:8765');
const [messageText, setMessageText] = useState("");
const [messageHistory, setMessageHistory] = useState([]);
const { sendMessage, sendJsonMessage, lastMessage, lastJsonMessage, readyState } = useWebSocket(ipServer);
const connectionStatus = {
[ReadyState.CONNECTING]: 'Connecting',
[ReadyState.OPEN]: 'Open',
[ReadyState.CLOSING]: 'Closing',
[ReadyState.CLOSED]: 'Closed',
[ReadyState.UNINSTANTIATED]: 'Uninstantiated',
}[readyState];
const paramCmd = {
type: 'setParam',
param1: 30,
param2: 2.3,
}
En los estados, recuperamos las funciones y estados de useWebSokcet
- sendMessage la función para enviar mensajes en formato String
- sendJsonMessage para enviar mensajes en formato JSON
- lastMessage contiene la respuesta del servidor en formato String
- lastJsonMessage contiene el último mensaje del servidor en formato JSON
- readyState contiene el estado de la conexión
También definimos una constante en formato Json paramCmd.
Utilizamos un hook useEffect para recuperar la dirección IP del dispositivo y gestionar los mensajes recibidos del servidor.
useEffect(() => {
const fetchIpAddress = async () => {
const ip = await NetworkInfo.getIPV4Address();
setIpAddress(ip);
console.log("ip adresses ; ", ip)
};
fetchIpAddress();
if (lastMessage !== null) {
setMessageHistory((prev) => prev.concat(lastMessage));
}
if (lastJsonMessage !== null) {
console.log(JSON.stringify(lastJsonMessage));
}
return () => {
};
}, [lastMessage, setMessageHistory,lastJsonMessage]);
Por último, creamos el renderizado de la aplicación con los siguientes elementos
- un texte pour afficher l’adresse IP de l’appareil
- un botón para enviar un mensaje JSON
- cuadro de texto para escribir el mensaje en formato de texto
- Botón Enviar para enviar el mensaje
- para introducir la dirección del servidor
- cuadro de texto para mostrar las respuestas del servidor
return (
<View style={styles.mainBody}>
<Text
style={styles.mainTitle}>
AC Websocket Terminal
</Text>
<ScrollView>
<View style={styles.deviceItem}>
<View style={{flex:2}}>
<Text style={styles.deviceName}>{ipAddress}</Text>
<Text style={styles.deviceInfo}>{connectionStatus}</Text>
</View>
<TouchableOpacity
onPress={() => sendJSON()}
disabled={readyState !== ReadyState.OPEN}
style={styles.deviceButton}>
<Text
style={styles.buttonText}>
Send JSON
</Text>
</TouchableOpacity>
</View>
<View
style={styles.inputBar}>
<TextInput
style={styles.textInput}
placeholder="Enter a message"
value={messageText}
onChangeText={(text) => setMessageText(text)
}
/>
<TouchableOpacity
onPress={() => sendMessage(messageText)}
disabled={readyState !== ReadyState.OPEN}
style={[styles.sendButton]}>
<Text
style={styles.buttonText}>
SEND
</Text>
</TouchableOpacity>
</View>
<TextInput
placeholder="Server IP"
onChangeText={setIpServer}
value={ipServer}
/>
<View style={{flex:1,minHeight:200}}>
<Text>Received Message:</Text>
<ScrollView style={styles.textOutput}>
{lastMessage ? <Text>last message : {lastMessage.data}</Text> : null}
{messageHistory.map((message, idx) => (
<Text key={idx}>{message ? message.data : null}</Text>
))}
</ScrollView>
</View>
</ScrollView>
</View>
);
Creación de un servidor WebSockets con Python
Para probar nuestra aplicación, creamos un servidor websockets en el PC
#!/usr/bin/env python
# python3 -m pip install websockets
import json
import asyncio
from websockets.server import serve
def getIpAddress():
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
ipaddress = s.getsockname()[0]
s.close()
return ipaddress
ipaddress = getIpAddress()
port = 8765
async def echo(websocket):
async for message in websocket:
print("received from {}:{} : ".format(websocket.remote_address[0],websocket.remote_address[1]) + message)
if('{' not in message):
await websocket.send(message)
else:
request = json.loads(message)
answer = {}
if(request['type'] == 'setParam'):
answer['type'] = request['type']
if(request['param1']<100 and request['param2']>1.2):
answer['valid'] = True
for key, val in request.items():
print("\t"+key+": ", val)
else:
answer['valid'] = False
else:
answer['type'] = 'unknown'
answer['valid'] = False
await websocket.send(json.dumps(answer))
async def main():
print("Server is activated on ws://{}:{}".format(ipaddress,port))
#async with serve(echo, "localhost", 8765):
async with serve(echo, "0.0.0.0", port):
await asyncio.Future() # run forever
asyncio.run(main())
Resultados
Gracias a esta aplicación, podemos enviar Strings y JSON al servidor y mostrar sus respuestas

Código completo para la comunicación WebSockets con React Native
/**
* https://reactnative.dev/docs/network
* https://www.npmjs.com/package/react-use-websocket
* https://github.com/robtaussig/react-use-websocket
* test on python
* https://websockets.readthedocs.io/en/stable/
*/
import React, {useState, useEffect, useCallback} from 'react';
import {
View,
ScrollView,
Text,
TextInput,
TouchableOpacity,
StyleSheet} from 'react-native';
import { NetworkInfo } from 'react-native-network-info'
import useWebSocket, { ReadyState } from 'react-use-websocket';
const WebsocketTerminal = () => {
const [ipAddress, setIpAddress] = useState('');
const [ipServer, setIpServer] = useState('ws://192.168.1.52:8765');
const [messageText, setMessageText] = useState("");
const [messageHistory, setMessageHistory] = useState([]);
const { sendMessage, sendJsonMessage, lastMessage, lastJsonMessage, readyState } = useWebSocket(ipServer);
useEffect(() => {
const fetchIpAddress = async () => {
const ip = await NetworkInfo.getIPV4Address();
setIpAddress(ip);
console.log("ip adresses ; ", ip)
};
fetchIpAddress();
if (lastMessage !== null) {
setMessageHistory((prev) => prev.concat(lastMessage));
}
if (lastJsonMessage !== null) {
console.log(JSON.stringify(lastJsonMessage));
}
return () => {
};
}, [lastMessage, setMessageHistory,lastJsonMessage]);
const connectionStatus = {
[ReadyState.CONNECTING]: 'Connecting',
[ReadyState.OPEN]: 'Open',
[ReadyState.CLOSING]: 'Closing',
[ReadyState.CLOSED]: 'Closed',
[ReadyState.UNINSTANTIATED]: 'Uninstantiated',
}[readyState];
const sendJSON = () => {
const paramCmd = {
type: 'setParam',
param1: 30,
param2: 2.3,
}
sendJsonMessage(paramCmd);
}
return (
<View style={styles.mainBody}>
<Text
style={styles.mainTitle}>
AC Websocket Terminal
</Text>
<ScrollView>
<View style={styles.deviceItem}>
<View style={{flex:2}}>
<Text style={styles.deviceName}>{ipAddress}</Text>
<Text style={styles.deviceInfo}>{connectionStatus}</Text>
</View>
<TouchableOpacity
onPress={() => sendJSON()}
disabled={readyState !== ReadyState.OPEN}
style={styles.deviceButton}>
<Text
style={styles.buttonText}>
Send JSON
</Text>
</TouchableOpacity>
</View>
<View
style={styles.inputBar}>
<TextInput
style={styles.textInput}
placeholder="Enter a message"
value={messageText}
onChangeText={(text) => setMessageText(text)
}
/>
<TouchableOpacity
onPress={() => sendMessage(messageText)}
disabled={readyState !== ReadyState.OPEN}
style={[styles.sendButton]}>
<Text
style={styles.buttonText}>
SEND
</Text>
</TouchableOpacity>
</View>
<TextInput
placeholder="Server IP"
onChangeText={setIpServer}
value={ipServer}
/>
<View style={{flex:1,minHeight:200}}>
<Text>Received Message:</Text>
<ScrollView style={styles.textOutput}>
{lastMessage ? <Text>last message : {lastMessage.data}</Text> : null}
{messageHistory.map((message, idx) => (
<Text key={idx}>{message ? message.data : null}</Text>
))}
</ScrollView>
</View>
</ScrollView>
</View>
);
}
export default WebsocketTerminal;
let BACKGROUND_COLOR = "#161616"; //191A19
let BUTTON_COLOR = "#346751"; //1E5128
let ERROR_COLOR = "#C84B31"; //4E9F3D
let TEXT_COLOR = "#ECDBBA"; //D8E9A8
var styles = StyleSheet.create({
mainBody: { flex: 1, justifyContent: 'center', backgroundColor: BACKGROUND_COLOR},
mainTitle:{
color: TEXT_COLOR,
fontSize: 30,
textAlign: 'center',
borderBottomWidth: 2,
borderBottomColor: ERROR_COLOR,
},
backgroundVideo: {
borderWidth: 2,
borderColor: 'red',
position: 'absolute',
top: 0,
left: 0,
bottom: 0,
right: 0,
},
webVideo: {
borderWidth: 2,
borderColor: 'green',
position: 'absolute',
top: 0,
left: 0,
bottom: 0,
right: 0,
},
buttonText: {
color: TEXT_COLOR,
fontWeight: 'bold',
fontSize: 12,
textAlign: 'center',
textAlignVertical: 'center',
},
sendButton: {
backgroundColor: BUTTON_COLOR,
padding: 15,
borderRadius: 15,
margin: 2,
paddingHorizontal: 20,
},
deviceItem: {
flexDirection: 'row',
flex: 3,
marginBottom: 2,
},
deviceName: {
fontSize: 14,
fontWeight: 'bold',
},
deviceInfo: {
fontSize: 8,
},
deviceButton: {
backgroundColor: '#2196F3',
padding: 10,
borderRadius: 10,
margin: 2,
paddingHorizontal: 20,
},
inputBar:{
flexDirection: 'row',
justifyContent: 'space-between',
margin: 5,
},
textInput:{
backgroundColor: '#888888',
margin: 2,
borderRadius: 15,
flex:3,
},
textOutput:{
backgroundColor: '#333333',
margin: 10,
borderRadius: 2,
borderWidth: 1,
borderColor: '#EEEEEE',
textAlignVertical: 'top',
}
});