I'm currently developing a backend UDP service in Go that communicates with a Flutter mobile app.
Here's the UDP service code:
package main
import (
"log"
"net"
"os"
"time"
)
func main() {
PORT := ":8080"
logger := log.New(os.Stdout, "", log.Ldate|log.Ltime)
udp_server, err := net.ResolveUDPAddr("udp4", PORT)
if err != nil {
logger.Fatalln(err.Error())
return
}
udp_connection, err := net.ListenUDP("udp4", udp_server)
if err != nil {
logger.Fatalln(err.Error())
return
}
defer udp_connection.Close()
buffer := make([]byte, 1024)
for {
n, addr, err := udp_connection.ReadFromUDP(buffer)
if err != nil {
udp_connection.WriteToUDP([]byte("Error reading from UDP connection"), addr)
}
buffer_string := string(buffer[0:n])
time_sent := time.Now()
time_sent_string := time_sent.String()
combined_string := buffer_string time_sent_string
data := []byte(combined_string);
logger.Println(combined_string);
_, err = udp_connection.WriteToUDP(data, addr)
if err != nil {
logger.Fatalln(err.Error())
return
}
}
}
As of now, the service is ran with Docker and can receive data being sent from the Flutter app, but the app can't receive data that the server is sending back.
Here's the Flutter code snippet for receiving and sending messages:
final socket = await RawDatagramSocket.bind(InternetAddress.anyIPv4, 0).onError((error, stackTrace) => throw error asSocketException);
final server = InternetAddress("10.0.2.2");
final port = 8080;
final data = [
deviceInfoData.deviceId,
DateTime.now().toUtc().toString()
];
DateTime current = DateTime.now();
late DateTime responseTime;
socket.send(data.toString().codeUnits, server, port);
String serverOut = "";
socket.listen((event) {
final datagram = socket.receive();
if (datagram != null) {
// print("Data sent to server: ${datagram.data}");
String message = String.fromCharCodes(datagram.data);
serverOut = message.split("]").last;
log(message);
socket.close();
} else {
socket.close();
}
});
The dockerfile for the UDP service is:
# Specifies a parent image
FROM golang:1.19.2-bullseye
# Creates an app directory to hold your app’s source code
WORKDIR /app
# Copies everything from your root directory into /app
COPY . .
# Installs Go dependencies
RUN go mod download
# Builds your app with optional configuration
RUN go build -o /udp-go
# Tells Docker which network port your container listens on
EXPOSE 8080
# Specifies the executable command that runs when the container starts
CMD [ "/udp-go" ]
And to run this, I use the following:
docker build --rm -t udp-go:alpha .
docker run -d -p 8080:8080/udp --name go-udp udp-go:alpha
I use the /udp
to map the udp port in the container to port 8080 on the docker host (https://docs.docker.com/config/containers/container-networking/)
However, this only allows me to send data to the service. I know this because checking the docker logs shows that the service is actually receiving data. if I am to run the service with plain old go run
instead of using docker, the app can send, and receive messages. How do I fix this?
Edit: I've tried adding in EXPOSE 8080\udp
to the dockerfile instead of just EXPOSE 8080
but it still has the same bug.
CodePudding user response:
Turns out the issue here is with the flutter code itself. The snippet below is the working one.
final socket = await RawDatagramSocket.bind(InternetAddress.anyIPv4, 0).onError((error, stackTrace) => throw error asSocketException);
final server = InternetAddress("10.0.2.2");
final port = 8080;
final data = [
deviceInfoData.deviceId,
DateTime.now().toUtc().toString()
];
DateTime current = DateTime.now();
late DateTime responseTime;
socket.send(data.toString().codeUnits, server, port);
String serverOut = "";
socket.listen((event) {
final datagram = socket.receive();
if (datagram != null) {
// print("Data sent to server: ${datagram.data}");
String message = String.fromCharCodes(datagram.data);
serverOut = message.split("]").last;
log(message);
}
},
onDone: () => socket.close(),
);
When working with UDP code, we must close the socket on onDone
and not while listening as the packet may not have been received fully yet by Dart.