英文:
Write to Client UDP Socket in Go
问题
我正在寻找一个在Go语言中使用UDP套接字进行客户端/服务器通信的好解决方案。
我在互联网上找到的示例向我展示了如何向服务器发送数据,但它们没有教我如何将数据发送回客户端。
为了演示,我的程序执行以下操作:
我的客户端程序在4444端口上创建一个套接字,如下所示:
con, err := net.Dial("udp", "127.0.0.1:4444")
我向服务器发送了一个字符串和本地地址,以便它可以打印字符串并发送一个OK消息。我在这里使用了gob:
enc := gob.NewEncoder(con)
enc.Encode(Data{"test", con.LocalAddr().String()})
我的Data结构如下所示:
type Data struct{
Msg string
Addr string
}
我的服务器监听4444端口并正确解码了Gob,但是我如何发送OK消息回去呢?我在服务器的.go文件中使用了客户端地址来做这个(在这里):
con, err := net.Dial("udp", data.Addr)
然后,我得到了一个错误代码:
write udp 127.0.0.1:35290: connection refused
当客户端尝试连接到服务器的4444端口时,客户端会创建一个具有随机数的端口(在这种情况下为35290),以便它们可以进行通信。我知道我不应该将客户端的地址传递给服务器,但是conn.RemoteAddress()不起作用。最好能找到一个可以发现客户端地址的解决方案。
注意:我知道有ReadFromUDP,所以我可以读取数据包。我应该读取它,发现客户端的地址,并将数据发送给Gob以便它可以解码吗?
英文:
I'm looking for a good solution for a client/server communication with UDP sockets in Go language.
The examples I found on the Internet show me how to send data to the server, but they do not teach how to send them back to the client.
To demonstrate, my program does the following:
My client program creates a socket on the 4444 port, like this:
con, err := net.Dial("udp", "127.0.0.1:4444")
I sent a string and the local address to the server, so it could print the string and send an OK message. I am using gob for this:
enc := gob.NewEncoder(con)
enc.Encode(Data{"test", con.LocalAddr().String()})
My Data struct looks like this:
type Data struct{
Msg string
Addr string
}
My server listens to the 4444 port and decodes the Gob correctly, but how can I send the OK message back? I'm using the client address to do so (on the server .go file):
con, err := net.Dial("udp", data.Addr)
Then, I get an error code:
write udp 127.0.0.1:35290: connection refused
When the client tries to connect to the Server's port 4444, the client creates a port with a random number (in this case, 35290) so they can communicate. I know I shouldn't be passing the client's address to the server, but conn.RemoteAddress() does not work. A solution that discovers the client's address would be most appreciated.
Obs.: I know there is ReadFromUDP, so I can read the package. Should I read it, discover the client's address, and send the data to Gob so it can decode it?
答案1
得分: 44
请查看以下示例,了解UDP上的客户端/服务器通信。sendResponse函数用于向客户端发送响应。
udpclient.go
package main
import (
"fmt"
"net"
"bufio"
)
func main() {
p := make([]byte, 2048)
conn, err := net.Dial("udp", "127.0.0.1:1234")
if err != nil {
fmt.Printf("Some error %v", err)
return
}
fmt.Fprintf(conn, "Hi UDP Server, How are you doing?")
_, err = bufio.NewReader(conn).Read(p)
if err == nil {
fmt.Printf("%s\n", p)
} else {
fmt.Printf("Some error %v\n", err)
}
conn.Close()
}
udpserver.go
package main
import (
"fmt"
"net"
)
func sendResponse(conn *net.UDPConn, addr *net.UDPAddr) {
_,err := conn.WriteToUDP([]byte("From server: Hello I got your message "), addr)
if err != nil {
fmt.Printf("Couldn't send response %v", err)
}
}
func main() {
p := make([]byte, 2048)
addr := net.UDPAddr{
Port: 1234,
IP: net.ParseIP("127.0.0.1"),
}
ser, err := net.ListenUDP("udp", &addr)
if err != nil {
fmt.Printf("Some error %v\n", err)
return
}
for {
_,remoteaddr,err := ser.ReadFromUDP(p)
fmt.Printf("Read a message from %v %s \n", remoteaddr, p)
if err != nil {
fmt.Printf("Some error %v", err)
continue
}
go sendResponse(ser, remoteaddr)
}
}
希望对你有帮助!
英文:
Check the below samples for client/server communication over UDP. The sendResponse routine is for sending response back to client.
udpclient.go
package main
import (
"fmt"
"net"
"bufio"
)
func main() {
p := make([]byte, 2048)
conn, err := net.Dial("udp", "127.0.0.1:1234")
if err != nil {
fmt.Printf("Some error %v", err)
return
}
fmt.Fprintf(conn, "Hi UDP Server, How are you doing?")
_, err = bufio.NewReader(conn).Read(p)
if err == nil {
fmt.Printf("%s\n", p)
} else {
fmt.Printf("Some error %v\n", err)
}
conn.Close()
}
udpserver.go
package main
import (
"fmt"
"net"
)
func sendResponse(conn *net.UDPConn, addr *net.UDPAddr) {
_,err := conn.WriteToUDP([]byte("From server: Hello I got your message "), addr)
if err != nil {
fmt.Printf("Couldn't send response %v", err)
}
}
func main() {
p := make([]byte, 2048)
addr := net.UDPAddr{
Port: 1234,
IP: net.ParseIP("127.0.0.1"),
}
ser, err := net.ListenUDP("udp", &addr)
if err != nil {
fmt.Printf("Some error %v\n", err)
return
}
for {
_,remoteaddr,err := ser.ReadFromUDP(p)
fmt.Printf("Read a message from %v %s \n", remoteaddr, p)
if err != nil {
fmt.Printf("Some error %v", err)
continue
}
go sendResponse(ser, remoteaddr)
}
}
答案2
得分: 4
你好,以下是翻译好的内容:
package main
import (
"bufio"
"fmt"
"net"
"time"
)
const proto, addr = "udp", ":8888"
func main() {
go func() {
conn, _ := net.ListenPacket(proto, addr)
buf := make([]byte, 1024)
n, dst, _ := conn.ReadFrom(buf)
fmt.Println("服务端接收", string(buf[:n]))
conn.WriteTo(buf, dst)
}()
time.Sleep(1 * time.Second)
conn, _ := net.Dial(proto, addr)
conn.Write([]byte("hello\n"))
buf, _, _ := bufio.NewReader(conn).ReadLine()
fmt.Println("客户端接收", string(buf))
}
希望对你有帮助!
英文:
hello_echo.go
package main
import (
"bufio"
"fmt"
"net"
"time"
)
const proto, addr = "udp", ":8888"
func main() {
go func() {
conn, _ := net.ListenPacket(proto, addr)
buf := make([]byte, 1024)
n, dst, _ := conn.ReadFrom(buf)
fmt.Println("serv recv", string(buf[:n]))
conn.WriteTo(buf, dst)
}()
time.Sleep(1 * time.Second)
conn, _ := net.Dial(proto, addr)
conn.Write([]byte("hello\n"))
buf, _, _ := bufio.NewReader(conn).ReadLine()
fmt.Println("clnt recv", string(buf))
}
答案3
得分: 2
这是一个UDP服务器和客户端的示例代码。你可以在以下链接中找到完整的代码:
https://gist.github.com/winlinvip/e8665ba888e2fd489ccd5a449fadfa73
server.go
这是服务器端的代码。它监听指定的端口(默认为8000),接收来自客户端的UDP数据包,并回复一个带有"Pong: "前缀的消息。
client.go
这是客户端的代码。它连接到指定的服务器端(默认为本地主机),发送一个包含"Hello, UDP server"消息的UDP数据包,并等待服务器的回复。
你可以通过运行这两个文件来测试UDP通信。
英文:
The gist is here:
https://gist.github.com/winlinvip/e8665ba888e2fd489ccd5a449fadfa73
server.go
/*
Usage:
go run server.go
See https://gist.github.com/winlinvip/e8665ba888e2fd489ccd5a449fadfa73
See https://stackoverflow.com/a/70576851/17679565
See https://github.com/ossrs/srs/issues/2843
*/
package main
import (
"fmt"
"net"
"os"
"strconv"
)
func main() {
serverPort := 8000
if len(os.Args) > 1 {
if v,err := strconv.Atoi(os.Args[1]); err != nil {
fmt.Printf("Invalid port %v, err %v", os.Args[1], err)
os.Exit(-1)
} else {
serverPort = v
}
}
addr := net.UDPAddr{
Port: serverPort,
IP: net.ParseIP("0.0.0.0"),
}
server, err := net.ListenUDP("udp", &addr)
if err != nil {
fmt.Printf("Listen err %v\n", err)
os.Exit(-1)
}
fmt.Printf("Listen at %v\n", addr.String())
for {
p := make([]byte, 1024)
nn, raddr, err := server.ReadFromUDP(p)
if err != nil {
fmt.Printf("Read err %v", err)
continue
}
msg := p[:nn]
fmt.Printf("Received %v %s\n", raddr, msg)
go func(conn *net.UDPConn, raddr *net.UDPAddr, msg []byte) {
_, err := conn.WriteToUDP([]byte(fmt.Sprintf("Pong: %s", msg)), raddr)
if err != nil {
fmt.Printf("Response err %v", err)
}
}(server, raddr, msg)
}
}
client.go
/*
Usage:
go run client.go
go run client.go 101.201.77.240
See https://gist.github.com/winlinvip/e8665ba888e2fd489ccd5a449fadfa73
See https://stackoverflow.com/a/70576851/17679565
See https://github.com/ossrs/srs/issues/2843
*/
package main
import (
"fmt"
"net"
"os"
"strings"
)
func main() {
serverEP := "127.0.0.1"
if len(os.Args) > 1 {
serverEP = os.Args[1]
}
if !strings.Contains(serverEP, ":") {
serverEP = fmt.Sprintf("%v:8000", serverEP)
}
conn, err := net.Dial("udp", serverEP)
if err != nil {
fmt.Printf("Dial err %v", err)
os.Exit(-1)
}
defer conn.Close()
msg := "Hello, UDP server"
fmt.Printf("Ping: %v\n", msg)
if _, err = conn.Write([]byte(msg)); err != nil {
fmt.Printf("Write err %v", err)
os.Exit(-1)
}
p := make([]byte, 1024)
nn, err := conn.Read(p)
if err != nil {
fmt.Printf("Read err %v\n", err)
os.Exit(-1)
}
fmt.Printf("%v\n", string(p[:nn]))
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论