Communication model
(a -- > B -- > A): a sends data to B through UDP (a can be a specified destination, or a broadcast message to b). B sends back a message to a according to the source address and port after receiving the message, which is such a simple communication process.
For the explanation of golang udp, please refer to the following https://colobu.com/2016/10/19/Go-UDP-Programming/ This document is very detailed. When the udp socket is connected, when it is unconnected, when it is read/write, and when it is read from UDP / writeto UDP are all explained. They are well written.
code demo
Server:
func main() { // Create monitoring sock, err := net.ListenUDP("udp4", &net.UDPAddr{ IP: net.IPv4(0, 0, 0, 0), Port: 9000, }) if err != nil { fmt.Println("listen udp failure!", err) return } defer sock.Close() for { // Read data data := make([]byte, 4096) readNum, rAddr, err := sock.ReadFromUDP(data) if err != nil { fmt.Println("read data failure!", err) continue } fmt.Println("read byte number:",readNum, "remote addr:", rAddr) fmt.Println("received: ", string(data[:readNum])) // send data sendBts := []byte("hello client!") _, err = sock.WriteToUDP(sendBts, rAddr) if err != nil { fmt.Println("send msg back failure!", err) return } else { fmt.Println("send msg mack ok.", string(sendBts), "to:", rAddr) } } }
Client
func main() { sock, err := net.DialUDP("udp", nil, &net.UDPAddr{ IP: net.IPv4(255, 255, 255, 255), // Broadcast address Port: 9000, }) // Create monitoring //soct, err := net.ListenUDP("udp4", &net.UDPAddr{ // IP: net.IPv4(0, 0, 0, 0), // Port: 9001, //}) if err != nil { fmt.Println("connect udp failure!", err) return } defer sock.Close() // send data sendBts := []byte("hello server!") _, err = sock.Write(sendBts) if err != nil { fmt.Println("send msg failure!", err) return } // receive data data := make([]byte, 4096) for { readNum, rAddr, err := sock.ReadFromUDP(data) if err != nil { fmt.Println("read udp failure!", err) return } fmt.Println("read byte number:", readNum, "from:", rAddr) fmt.Println("received: ", string(data[:readNum])) } }
Problem presentation
Run the demo above:
Server side
read byte number: 13 remote addr: 10.200.2.50:54404 received: hello server! send msg mack ok. hello client! to: 10.200.2.50:54404
Client
// nothing
We found that the client didn't output anything, so we have a problem. The server clearly sent the data, and also specified the destination ip and port number! Why didn't the client receive it? When dial ing on the client side, it will not listen to the local port when sending broadcast messages?? Or is it not the same network card that listens when broadcasting messages? Change the client code with the problem.
// Enable the code commented out by the client func main() { // Create monitoring sock, err := net.ListenUDP("udp4", &net.UDPAddr{ IP: net.IPv4(0, 0, 0, 0), Port: 9001, // When testing on the same host, bind different ports with the server; if it is a different host, use the same port }) if err != nil { fmt.Println("connect udp failure!", err) return } defer sock.Close() // send data sendBts := []byte("hello server!") _, err = sock.WriteToUDP(sendBts, &net.UDPAddr{ IP: net.IPv4(255, 255, 255, 255), Port: 9000, }) if err != nil { fmt.Println("send msg failure!", err) return } // receive data data := make([]byte, 4096) for { readNum, rAddr, err := sock.ReadFromUDP(data) if err != nil { fmt.Println("read udp failure!", err) return } fmt.Println("read byte number:", readNum, "from:", rAddr) fmt.Println("received: ", string(data[:readNum])) } }
Run again
Server side
read byte number: 13 remote addr: 10.200.2.50:54404 received: hello server! send msg mack ok. hello client! to: 10.200.2.50:54404
Client
received: hello client!
The result really confirms the conjecture that we can't receive messages without listening. Why didn't dial listen? Remember that c code implicitly binds (see https://stackoverflow.com/questions/54443823/udp-socket-sendto-implicit-bind,https://www.cnblogs.com/skyfsm/p/6287787.html )Will there be different encapsulation between languages? Let's take a look at the source code of golang.
When you see dialUDP and listenUDP, the parameters in the red box are different, and others can be said to be the same. Continue to look at the internetsocket - > socket method
Note that the code in the red box is for udp listening / binding, but there is a precondition: there is local addr(laddr) and there is no remote addr(raddr).
Then change the DialUDP code of the client
sock, err := net.DialUDP("udp", &net.UDPAddr{ IP: net.IPv4(0,0,0,0), Port: 9001, }, nil)
Run the client's code again.
connect udp failure! dial udp 0.0.0.0:9001: missing address
Got an error with missing address, which means DialUDP does not support implicit binding.
summary
When using udp programming, if you simply send data, you can use DialUDP to get the socket handle, and then call write method to send data. If you want to receive messages, whether the client or the server, you must use ListenUDP to listen / bind before receiving messages.