我需要創建UDP連接,通過它我可以同時寫入和讀取數據包。 (使用不同夠程並用GOMAXPROCS(n),其中N> 1)首先嚐試是這樣的:在Go中處理讀/寫udp連接
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]}
}
}
}
所以讀取包我用分組:= < - 入站和寫入conn.WriteTo (data_bytes,remote_addr)。但race detector在連接上同時讀取/寫入時發出警告。所以我重寫代碼,是這樣的:
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]}
}
}
}
}
此代碼將不再觸發競爭狀態,但有如果沒有入站數據包阻塞夠程的風險。我所看到的解決方案是在調用ReadFromUDP之前調用諸如SetReadDeadline(time.Now()+ 10 * time.Millisecond)。這段代碼可能會起作用,但我不太喜歡它。有沒有更優雅的方法來解決這個問題?
UPD:警告消息:
==================
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>
==================
確切的錯誤是什麼? – Arjan
這不是一個錯誤,而是警告。如果我用--race標誌運行第一個例子,我會從比賽檢測中得到警告。 (我會嘗試重新創建這個警告並將它粘貼到下一個註釋中) – user3234005
它可能會抱怨你在兩個goroutine(它的指針)中訪問同一個變量,但是實現Conn的任何東西都可以處理多個goroutines來訪問它:「Multiple goroutines可能會同時在康恩上調用方法。「 – Arjan