udp编程的那些事与golang udp的实践
udp编程的那些事与golang udp的实践tcp/ip大协议中,tcp编程大家应该比较熟,应用的场景也很多,但是udp在现实中,应用也不少,而在大部分博文中,都很少对udp的编程进行研究,最近研究了一下udp编程,正好做个记录。 tcp Vs udptcp和udp都是著名的传输协议,他们都是基于ip协议,都在OSI模型中传输层。tcp我们都很清楚,它提供了可靠的数据传输,而udp我们也知道,它不提供数据传输的可靠性,只是尽力传输。 他们的特性决定了它们很大的不同,tcp提供可靠性传输,有三次握手,4次分手,相当于具有逻辑上的连接,可以知道这个tcp连接的状态,所以我们都说tcp是面向连接的socket,而udp没有握手,没有分手,也不存在逻辑上的连接,所以我们也都说udp是非面向连接的socket。 udp协议udp的首部2 2 (byte) +---+---+---+---+---+---+---+---+ - | src port | dst port | | +---+---+---+---+---+---+---+---+ 8(bytes) | length | check sum | | +---+---+---+---+---+---+---+---+ - | | + data + | | +---+---+---+---+---+---+---+---+ udp的首部真的很简单,头2个字节表示的是原端口,后2个字节表示的是目的端口,端口是系统层区分进程的标识。接着是udp长度,最后就是校验和,这个其实很重要,现在的系统都是默认开启udp校验和的,所以我们才能确保udp消息传输的完整性。如果这个校验和关闭了,那会让我们绝对会很忧伤,因为udp不仅不能保证数据一定到达,还不能保证即使数据到了,这个数据是否是正确的。比如:我在发送端发送了“hello”,而接收端却接收到了“hell”。如果真的是这样,我们就必须自己去校验数据的正确性。还好udp默认开发了校验,我们可以保证udp的数据完整性。 udp数据的封装+---------+ | 应用数据 | +---------+ | | v v +---------+---------+ | udp首部 | 应用数据 | +---------+---------+ | | v UDP数据报 v +---------+---------+---------+ | ip首部 | udp首部 | 应用数据 | +---------+---------+---------+ | | v IP数据报 v +---------+---------+---------+---------+---------+ |以太网首部 | ip首部 | udp首部 | 应用数据 |以太网尾部 | +---------+---------+---------+---------+---------+ | 14 20 8 4 | | -> 以太网帧 <- | 数据的封装和tcp是一样,应用层的数据加上udp首部,构成udp数据报,再加上ip首部构成ip数据报,最后加上以太网首部和尾部构成以太网帧,经过网卡发送出去。 Golang udp实践实践出真知,编程就需要多实践,才能体会其中的奥妙。 echo客户端和服务端echo服务,实现数据包的回显,这是很多人网络编程起点,因为这个服务足够简单,但又把网络的数据流都过了一遍,这里也用go udp实现一个echo服务。
package main import ( "flag" "fmt" "log" "net" ) var addr = flag.String("addr",":10000","udp server bing address") func init() { log.SetFlags(log.LstdFlags | log.Lshortfile) flag.Parse() } func main() { //Resolving address udpAddr,err := net.ResolveUDPAddr("udp",*addr) if err != nil { log.Fatalln("Error: ",err) } // Build listining connections conn,err := net.ListenUDP("udp",udpAddr) if err != nil { log.Fatalln("Error: ",err) } defer conn.Close() // Interacting with one client at a time recvBuff := make([]byte,1024) for { log.Println("Ready to receive packets!") // Receiving a message rn,rmAddr,err := conn.ReadFromUDP(recvBuff) if err != nil { log.Println("Error:",err) return } fmt.Printf("<<< Packet received from: %s,data: %sn",rmAddr.String(),string(recvBuff[:rn])) // Sending the same message back to current client _,err = conn.WriteToUDP(recvBuff[:rn],rmAddr) if err != nil { log.Println("Error:",err) return } fmt.Println(">>> Sent packet to: ",rmAddr.String()) } }
package main import ( "flag" "fmt" "log" "net" ) var raddr = flag.String("raddr","127.0.0.1:10000","remote server address") func init() { log.SetFlags(log.LstdFlags | log.Lshortfile) flag.Parse() } func main() { // Resolving Address remoteAddr,*raddr) if err != nil { log.Fatalln("Error: ",err) } // Make a connection tmpAddr := &net.UDPAddr{ IP: net.ParseIP("127.0.0.1"),Port: 0,} conn,err := net.DialUDP("udp",tmpAddr,remoteAddr) // Exit if some error occured if err != nil { log.Fatalln("Error: ",err) } defer conn.Close() // write a message to server _,err = conn.Write([]byte("hello")) if err != nil { log.Println(err) } else { fmt.Println(">>> Packet sent to: ",*raddr) } // Receive response from server buf := make([]byte,1024) rn,err := conn.ReadFromUDP(buf) if err != nil { log.Println(err) } else { fmt.Printf("<<< %d bytes received from: %v,rn,string(buf[:rn])) } }
package main import ( "flag" "fmt" "log" "net" ) var ( laddr = flag.String("laddr","127.0.0.1:9000","local server address") raddr = flag.String("raddr","remote server address") ) func init() { log.SetFlags(log.LstdFlags | log.Lshortfile) flag.Parse() } func main() { // Resolving Address localAddr,*laddr) if err != nil { log.Fatalln("Error: ",err) } remoteAddr,err) } // Build listening connections conn,localAddr) // Exit if some error occured if err != nil { log.Fatalln("Error: ",err = conn.WriteToUDP([]byte("hello"),remoteAddr) if err != nil { log.Println(err) } else { fmt.Println(">>> Packet sent to: ",remAddr,string(buf[:rn])) } } 这里实现echo的服务端和客户端,和tcp的差不多,但是有一些小细节需要注意。 参考golang doc (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |