常见的演示DEMO

conn, err := net.ListenUDP("udp", &net.UDPAddr{Port: 8866})
if err != nil {
	log.Fatalf("Udp Service listen report udp fail:%v", err)
}
defer conn.Close()
for {
	data := make([]byte, 1024*4)
	n, remoteAddr, err := conn.ReadFromUDP(data)
	if err == nil {
		// ... 做点什么
           conn.WriteToUDP(data[:n], remoteAddr)
	}
}

常见问题:

  1. 会产生大量内存消耗。引起频繁GC。
  2. 收到数据后处理不应该在for循环内部。因为如果数据处理时间过长,就会拥塞,甚至数据丢失

兼容协助中使用的解决方案,知识点copy

golang 为了避免每一层的处理数据都要在内存里建立相同数据的副本。采用了引用的方式传递。也就是slice的存在的意义!它大量节约了内存!天才般的设计!

这里conn.ReadFromUDP(data)后data里放的其实是底层缓冲区内的数据引用。操作data实际上是在操作底层缓冲区。

所以我们在操作data前一定要先将data里的数据读入新的变量里,实现私有化,再交给协程处理。否则在协程未启动完成前,data里的数据可能因为进入新的循环,而被刷新!

不幸的是,简单的=是不能将data 私有化的。只能make一个空白的slice,再将data逐个复制进来。这个操作golang已为我们封装好了一个函数,它就是:copy

conn, err := net.ListenUDP("udp", &net.UDPAddr{Port: 8866})
if err != nil {
	log.Fatalf("Udp Service listen report udp fail:%v", err)
}
defer conn.Close()
var data = make([]byte, 1024*4)
var raw []byte
for {
	n, remoteAddr, err := conn.ReadFromUDP(data)
	if err == nil {
		raw = make([]byte,n)
		copy(raw,data[:n])
		go func (){
			// ... 拿 raw 做点什么
			conn.WriteToUDP(raw, remoteAddr)
		}()
	}
}