I need to create a UDP connection through which I can write and read packets at the same time. (using different goroutines and with GOMAXPROCS (n), where n> 1) The first attempt was something like this:
func new_conn(port, chan_buf int) (conn *net.UDPConn, inbound chan Packet, err error) { inbound = make(chan Packet, chan_buf) conn, err = net.ListenUDP("udp4", &net.UDPAddr{Port: port}) if err != nil {return} go func () { for { b := make([]byte, UDP_PACKET_SIZE) n, addr, err := conn.ReadFromUDP(b) if err != nil { log.Printf("Error: UDP read error: %v", err) continue } inbound <- Packet{addr, b[:n]} } } }
So, to read the package, I used the package: = <- inbound and wrote conn.WriteTo (data_bytes, remote_addr) . But the race detector warns of simultaneous read / write when connected. So I rewrite the code like this:
func new_conn(port, chan_buf int) (inbound, outbound chan Packet, err error) { inbound = make(chan Packet, chan_buf) outbound = make(chan Packet, chan_buf) conn, err = net.ListenUDP("udp4", &net.UDPAddr{Port: port}) if err != nil {return} go func () { for { select { case packet := <- outbound: _, err := conn.WriteToUDP(packet.data, packet.addr) if err != nil { log.Printf("Error: UDP write error: %v", err) continue } default: b := make([]byte, UDP_PACKET_SIZE) n, addr, err := conn.ReadFromUDP(b) if err != nil { log.Printf("Error: UDP read error: %v", err) continue } inbound <- Packet{addr, b[:n]} } } } }
This code will no longer trigger a race condition, but has the risk of blocking goroutine if there are no incoming packets. The only solution I see is to call something like SetReadDeadline (time.Now () + 10 * time.Millisecond) before calling ReadFromUDP. This code will probably work, but I don't like it. Are there any more elegant ways to solve this problem?
UPD: Warning:
================== WARNING: DATA RACE Read by goroutine 553: net.ipToSockaddr() /usr/local/go/src/pkg/net/ipsock_posix.go:150 +0x18a net.(*UDPAddr).sockaddr() /usr/local/go/src/pkg/net/udpsock_posix.go:45 +0xd9 net.(*UDPConn).WriteToUDP() /usr/local/go/src/pkg/net/udpsock_posix.go:123 +0x4df net.(*UDPConn).WriteTo() /usr/local/go/src/pkg/net/udpsock_posix.go:139 +0x2f6 <traceback which points on conn.WriteTo call> Previous write by goroutine 556: syscall.anyToSockaddr() /usr/local/go/src/pkg/syscall/syscall_linux.go:383 +0x336 syscall.Recvfrom() /usr/local/go/src/pkg/syscall/syscall_unix.go:223 +0x15c net.(*netFD).ReadFrom() /usr/local/go/src/pkg/net/fd_unix.go:227 +0x33c net.(*UDPConn).ReadFromUDP() /usr/local/go/src/pkg/net/udpsock_posix.go:67 +0x164 <traceback which points on conn.ReadFromUDP call> Goroutine 553 (running) created at: <traceback> Goroutine 556 (running) created at: <traceback> ==================