Neste tutorial, vamos configurar a comunicação usando o protocolo UDP em um aplicativo React Native. O aplicativo React Native pode atuar como um servidor ou cliente UDP. Usamos um computador com um script Python como parceiro de comunicação.
Configurar o React Native
Primeiro, crie um projeto React Native UDPTerminalApp
Instalar as bibliotecas udp e netinfo
npm install react-native-udp npm install react-native-network-info
Descrição do código de aplicação
Importação
Para utilizar as bibliotecas, primeiro importamos o seu código.
import dgram from 'react-native-udp'
import UdpSocket from 'react-native-udp/lib/types/UdpSocket.js';
import { NetworkInfo } from 'react-native-network-info'
Componente principal
Em seguida, criamos o componente funcional que nos permitirá gerir a comunicação do servidor
const UDPTerminal = () => {
const [isServer, setIsServer] = useState(false);
const [connectionStatus, setConnectionStatus] = useState('');
const [socket, setSocket] = useState<UdpSocket>();
const [ipAddress, setIpAddress] = useState('');
const [ipServer, setIpServer] = React.useState('');
const [messageText, setMessageText] = useState("");
const [messageToSend, setMessageToSend] = useState("Hello from server");
const [receivedMessage, setReceivedMessage] = useState("");
- isServer é True se a aplicação se comportar como um servidor e false se se comportar como um cliente
- connectionStatus apresenta o estado da ligação
- socket contém a variável de socket para a comunicação
- ipAddress contém o endereço IP do dispositivo Android na rede
- ipServer contém o endereço IP introduzido na interface
- messageText contém o texto digitado na interface
- messageToSend contém a mensagem a enviar ao cliente ou ao servidor
- receivedMessage contém mensagens recebidas do cliente ou do servidor
Gestão da comunicação UDP
O código utilizado para gerir a comunicação UDP, seja no modo servidor ou cliente, está inteiramente contido num hook useEffect.
useEffect(() => {
const fetchIpAddress = async () => {
const ip = await NetworkInfo.getIPV4Address();
setIpAddress(ip);
console.log("ip adresses ; ", ip)
};
fetchIpAddress();
if (isServer) {
// Configure app as server
const server = dgram.createSocket('udp4');
server.on('message', (data, rinfo) => {
server.send(messageToSend, undefined, undefined, rinfo?.port, rinfo?.address, (error) => {
if (error) {
console.log('Error sending message:', error);
} else {
console.log('Message sent correctly');
}
});
console.log('Received message:', data.toString());
setReceivedMessage(receivedMessage => receivedMessage+data.toString()+"\n")
});
server.on('listening', () => {
console.log('Server listening on port:', server.address().port);
setConnectionStatus(`Server listening on port ${server.address().port}`);
});
try{
setReceivedMessage("");
server.bind(8888);
setSocket(server);
}catch(error){
console.log("error binding server",error);
}
} else {
setConnectionStatus(`Server disconnected`);
// Configure app as client
const client = dgram.createSocket('udp4');
try{
setReceivedMessage("");
client.bind(8887);
setSocket(client);
}catch(error){
console.log("error binding client",error);
}
}
return () => {
socket && socket.close();
};
}, [isServer, messageToSend, messageText]);
A função fetchIpAdress é utilizada para obter o endereço IP do dispositivo.
No modo de servidor
- criamos o socket dgram.createSocket
- quando uma mensagem é recebida: enviamos messageToSend ao cliente
- De seguida, apresentamos a mensagem recebida
- ligamos o servidor à porta 8888
No modo cliente
- criamos o socket dgram.createSocket
- ligamos o cliente ao porto 8887
Na seguinte função
- enviamos a mensagem messageToSend para o servidor
- depois aguardamos a resposta, que apresentamos em receivedMessage
Função de envio de mensagens
Também definimos uma função que actualiza a mensagem enviada no modo Servidor e envia a mensagem no modo Cliente.
const sendMessage = () => {
setMessageToSend(messageText);
if (isServer) return;
const client = socket;
console.log("send message to "+ipServer)
client.send(messageToSend, undefined, undefined, 8888, ipServer, (error) => {
if (error) {
console.log('Error sending message:', error);
} else {
console.log('Message sent correctly');
}
});
client.on('message', async (message: { toString: () => string; }) => {
setReceivedMessage(receivedMessage+message.toString()+"\n")
});
};
Definição do ecrã
Por fim, a interface gráfica da aplicação é definida da seguinte forma:
- O título da aplicação
- O endereço IP do dispositivo
- Um botão para selecionar o modo cliente ou servidor
- Uma inserção para editar a mensagem a enviar
- Um botão de envio
- Uma inserção para especificar o endereço IP do servidor no modo de cliente
- Uma caixa de texto para apresentar as mensagens recebidas
return (
<View style={styles.mainBody}>
<Text
style={styles.mainTitle}>
AC UDP Terminal
</Text>
<ScrollView>
<View style={styles.deviceItem}>
<View>
<Text style={styles.deviceName}>{ipAddress}</Text>
<Text style={styles.deviceInfo}>{connectionStatus}</Text>
</View>
<TouchableOpacity
onPress={() => setIsServer(!isServer)}
style={styles.deviceButton}>
<Text
style={styles.buttonText}>
{isServer ? 'Server' : 'Client'}
</Text>
</TouchableOpacity>
</View>
<View
style={styles.inputBar}>
<TextInput
style={styles.textInput}
placeholder="Enter a message"
value={messageText}
onChangeText={(text) => setMessageText(text)
}
/>
<TouchableOpacity
onPress={() => sendMessage()
}
style={[styles.sendButton]}>
<Text
style={styles.buttonText}>
SEND
</Text>
</TouchableOpacity>
</View>
<TextInput
placeholder="Server IP"
onChangeText={setIpServer}
value={ipServer}
/>
<Text>Received Message:</Text>
<TextInput
editable = {false}
multiline
numberOfLines={20}
maxLength={300}
style={styles.textOutput} >
{receivedMessage}
</TextInput>
</ScrollView>
</View>
);
N.B.: o estilo da interface é definido na secção
Cliente UDP React-Native – Servidor UDP Python
Neste exemplo, configuramos a aplicação como um cliente e o computador como um servidor. Enviaremos uma mensagem da aplicação para o servidor, que enviará uma resposta ao cliente.
Código do servidor UDP Python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
localIP = "0.0.0.0" #"127.0.0.1"
localPort = 8888
bufferSize = 1024
msgFromServer = "Hello UDP Client"
bytesToSend = str.encode(msgFromServer)
# Create a datagram socket
UDPServerSocket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
# Bind to address and ip
UDPServerSocket.bind((localIP, localPort))
print("UDP server up and listening on port {}".format(localPort))
# Listen for incoming datagrams
while(True):
data,addr = UDPServerSocket.recvfrom(bufferSize)
print("{} > {}".format(addr,data))
# Sending a reply to client
UDPServerSocket.sendto(bytesToSend, addr)
Nota: Para escutar em todos os endereços locais, utilizamos 0.0.0.0. Se quiser testar a comunicação entre o cliente e o servidor no mesmo computador, pode utilizar o endereço 127.0.0.1.
Na aplicação, na caixa ServerIp, introduza o endereço IP do computador (aqui: 192.168.1.70). Em seguida, modifique a mensagem a enviar e prima o botão ENVIAR.

Terminal Python
UDP server up and listening on port 8888
('192.168.1.5', 8887) > b'Hello server'
('192.168.1.5', 8887) > b'Hello server'
No terminal Python, recebemos a mensagem “Hello server” (Olá servidor) enviada pela aplicação. O servidor UDP envia de volta “Hello UDP Client” (Olá cliente UDP).
Servidor UDP React-Native – Cliente UDP Python
Aqui, configuramos a aplicação como um servidor e o computador como um cliente. No código Python, introduzimos o endereço IP do servidor.
Cliente UDP Python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
import time
HOST = "192.168.1.5" #Server IP #"127.0.0.1" local address
PORT = 8888
bufferSize = 1024
counter=0
while True:
# Create a UDP socket at client side
with socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM) as client:
# Send to server using created UDP socket
client.sendto(str.encode("client counter : "+str(counter)), (HOST,PORT))
data,addr= client.recvfrom(bufferSize)
msg = "{} > {}".format(addr,data)
print(msg)
counter+=1
time.sleep(1)

Terminal Python
('192.168.1.5', 8888) > b'Hello client '
('192.168.1.5', 8888) > b'Hello client '
Código completo da aplicação
App.tsx
/**
* npm install react-native-udp
* npm install react-native-network-info
*
*/
import React, {useState, useEffect} from 'react';
import {
View,
ScrollView,
Text,
TextInput,
PermissionsAndroid,
Platform,
TouchableOpacity } from 'react-native';
import dgram from 'react-native-udp'
import UdpSocket from 'react-native-udp/lib/types/UdpSocket.js';
import { NetworkInfo } from 'react-native-network-info'
import {styles} from "./src/styles/styles.jsx"
const UDPTerminal = () => {
const [isServer, setIsServer] = useState(false);
const [connectionStatus, setConnectionStatus] = useState('');
const [socket, setSocket] = useState<UdpSocket>();
const [ipAddress, setIpAddress] = useState('');
const [ipServer, setIpServer] = React.useState('');
const [messageText, setMessageText] = useState("");
const [messageToSend, setMessageToSend] = useState("Hello from server");
const [receivedMessage, setReceivedMessage] = useState("");
useEffect(() => {
const fetchIpAddress = async () => {
const ip = await NetworkInfo.getIPV4Address();
setIpAddress(ip);
console.log("ip adresses ; ", ip)
};
fetchIpAddress();
if (isServer) {
// Configure app as server
const server = dgram.createSocket('udp4');
server.on('message', (data, rinfo) => {
server.send(messageToSend, undefined, undefined, rinfo?.port, rinfo?.address, (error) => {
if (error) {
console.log('Error sending message:', error);
} else {
console.log('Message sent correctly');
}
});
console.log('Received message:', data.toString());
if(receivedMessage.length>300){
setReceivedMessage("");
}
setReceivedMessage(receivedMessage => receivedMessage+data.toString()+"\n")
});
server.on('listening', () => {
console.log('Server listening on port:', server.address().port);
setConnectionStatus(`Server listening on port ${server.address().port}`);
});
try{
setReceivedMessage("");
server.bind(8888);
setSocket(server);
}catch(error){
console.log("error binding server",error);
}
} else {
setConnectionStatus(`Server disconnected`);
// Configure app as client
const client = dgram.createSocket('udp4');
try{
setReceivedMessage("");
client.bind(8887);
setSocket(client);
}catch(error){
console.log("error binding client",error);
}
}
return () => {
socket && socket.close();
};
}, [isServer, messageToSend, messageText]);
const sendMessage = () => {
setMessageToSend(messageText);
if (isServer) return;
const client = socket;
console.log("send message to "+ipServer)
client.send(messageToSend, undefined, undefined, 8888, ipServer, (error) => {
if (error) {
console.log('Error sending message:', error);
} else {
console.log('Message sent correctly');
}
});
client.on('message', async (message: { toString: () => string; }) => {
if(receivedMessage.length>300){
setReceivedMessage("");
}
setReceivedMessage(receivedMessage+message.toString()+"\n")
});
};
return (
<View style={styles.mainBody}>
<Text
style={styles.mainTitle}>
AC UDP Terminal
</Text>
<ScrollView>
<View style={styles.deviceItem}>
<View>
<Text style={styles.deviceName}>{ipAddress}</Text>
<Text style={styles.deviceInfo}>{connectionStatus}</Text>
</View>
<TouchableOpacity
onPress={() => setIsServer(!isServer)}
style={styles.deviceButton}>
<Text
style={styles.buttonText}>
{isServer ? 'Server' : 'Client'}
</Text>
</TouchableOpacity>
</View>
<View
style={styles.inputBar}>
<TextInput
style={styles.textInput}
placeholder="Enter a message"
value={messageText}
onChangeText={(text) => setMessageText(text)
}
/>
<TouchableOpacity
onPress={() => sendMessage()
}
style={[styles.sendButton]}>
<Text
style={styles.buttonText}>
SEND
</Text>
</TouchableOpacity>
</View>
<TextInput
placeholder="Server IP"
onChangeText={setIpServer}
value={ipServer}
/>
<Text>Received Message:</Text>
<TextInput
editable = {false}
multiline
numberOfLines={20}
maxLength={300}
style={styles.textOutput} >
{receivedMessage}
</TextInput>
</ScrollView>
</View>
);
}
export default UDPTerminal;
style.jsx
/* ./src/styles/styles.jsx */
import {StyleSheet, Dimensions} from 'react-native';
/**
* links to palette
* https://colorhunt.co/palette/161616346751c84b31ecdbba
*
*/
//parameters
let BACKGROUND_COLOR = "#161616"; //191A19
let BUTTON_COLOR = "#346751"; //1E5128
let ERROR_COLOR = "#C84B31"; //4E9F3D
let TEXT_COLOR = "#ECDBBA"; //D8E9A8
const windowHeight = Dimensions.get('window').height;
export const styles = StyleSheet.create({
mainBody: {
flex: 1,
justifyContent: 'center',
height: windowHeight,
color:TEXT_COLOR,
backgroundColor: BACKGROUND_COLOR,
},
mainTitle:{
color: TEXT_COLOR,
fontSize: 30,
textAlign: 'center',
borderBottomWidth: 2,
borderBottomColor: ERROR_COLOR,
},
scanButton: {
backgroundColor: BUTTON_COLOR,
paddingBottom: 10,
paddingTop: 10,
borderRadius: 10,
margin: 2,
marginBottom: 10,
marginTop: 10,
paddingHorizontal: 20,
fontWeight: 'bold',
fontSize: 12,
},
buttonText: {
color: TEXT_COLOR,
fontWeight: 'bold',
fontSize: 12,
textAlign: 'center',
},
noDevicesText: {
color: TEXT_COLOR,
textAlign: 'center',
marginTop: 10,
fontStyle: 'italic',
},
deviceItem: {
flexDirection: 'row',
justifyContent: 'space-between',
marginBottom: 2,
},
deviceName: {
color: TEXT_COLOR,
fontSize: 14,
fontWeight: 'bold',
},
deviceInfo: {
color: TEXT_COLOR,
fontSize: 10,
},
deviceButton: {
backgroundColor: BUTTON_COLOR,
padding: 10,
borderRadius: 10,
margin: 2,
paddingHorizontal: 20,
fontWeight: 'bold',
fontSize: 12,
},
inputBar:{
flexDirection: 'row',
justifyContent: 'space-between',
margin: 5,
},
textInput:{
backgroundColor: '#888888',
margin: 2,
borderRadius: 15,
flex:3,
},
sendButton: {
backgroundColor: BUTTON_COLOR,
padding: 15,
borderRadius: 15,
margin: 2,
paddingHorizontal: 20,
},
textOutput:{
backgroundColor: '#333333',
margin: 10,
borderRadius: 2,
borderWidth: 1,
borderColor: '#EEEEEE',
textAlignVertical: 'top',
}
});
Aplicações
- Controle o seu projeto Arduino, ESP32 ou Raspberry Pi com uma aplicação