英文:
Flutter app can send to UDP server in a docker container but can't receive data being sent from the server
问题
我目前正在开发一个使用Go语言编写的后端UDP服务,该服务与Flutter移动应用程序进行通信。
以下是UDP服务的代码:
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
}
}
}
到目前为止,该服务在Docker中运行,并且可以接收从Flutter应用程序发送的数据,但是应用程序无法接收服务器发送的数据。
以下是用于接收和发送消息的Flutter代码片段:
final socket = await RawDatagramSocket.bind(InternetAddress.anyIPv4, 0).onError((error, stackTrace) => throw error as SocketException);
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();
}
});
UDP服务的Dockerfile如下:
# 指定父镜像
FROM golang:1.19.2-bullseye
# 创建一个app目录来保存应用程序的源代码
WORKDIR /app
# 将根目录中的所有内容复制到/app中
COPY . .
# 安装Go依赖项
RUN go mod download
# 使用可选配置构建应用程序
RUN go build -o /udp-go
# 告诉Docker容器监听的网络端口
EXPOSE 8080
# 指定容器启动时运行的可执行命令
CMD ["/udp-go"]
要运行它,我使用以下命令:
docker build --rm -t udp-go:alpha .
docker run -d -p 8080:8080/udp --name go-udp udp-go:alpha
我使用/udp
将容器中的UDP端口映射到Docker主机上的端口8080(https://docs.docker.com/config/containers/container-networking/)。
然而,这只允许我向服务发送数据。我知道这一点是因为检查Docker日志显示服务实际上正在接收数据。如果我使用普通的go run
而不是使用Docker运行服务,应用程序可以发送和接收消息。我该如何解决这个问题?
编辑:我尝试在Dockerfile中添加EXPOSE 8080/udp
而不仅仅是EXPOSE 8080
,但仍然存在相同的错误。
英文:
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.
答案1
得分: 0
问题在于flutter代码本身。下面的代码片段是可工作的。
final socket = await RawDatagramSocket.bind(InternetAddress.anyIPv4, 0).onError((error, stackTrace) => throw error as SocketException);
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(),
);
在处理UDP代码时,我们必须在onDone
中关闭socket,而不是在监听时关闭,因为Dart可能尚未完全接收到数据包。
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论