udp socket - golang

         前面说了几个tcp模式下的socket新手易错点,今天就来看看udp的新手易错点。

         先让我们看一段代码:

       

        l, e := net.ListenPacket("udp", ":9090")
	if e != nil {
		fmt.Println(e)
	}
	b := make([]byte, 10)
	for {
		n,a, e := l.ReadFrom(b)
		if n == 0 || e == io.EOF {
			break
		}
		fmt.Println(n,a)
	}
	fmt.Println(string(b))

       与dial不同,go对tcp和udp分别封装进了net.Listen()和net.ListenPacket(),具体关系大家可以看: net包 listen - golang

       在这篇里有画一个简单关系图。

       上面代码,是我们仿照tcp模式的sokcet写的一个例子,那这个例子是不是会和当初tcp一样执行正确呢。让我们看看输出:

        在这里我们发送的还是tcp中提到的(我是tcp socket测试),如果你自己执行,你会发现udp情况下Read一次后程序就陷入了阻塞,而不像tcp那样读完数据后才进入阻塞。

         之所以有这种不同变化是因为他们不同的发送形式,tcp一般以流的形式发送,而udp一般是以数据报的形式发送的。所以他在读取一次后即使没有读完,程序也会把后续数据丢弃。具体可以看sock_posix.go这个文件的socket函数:

        

if laddr != nil && raddr == nil {
		switch sotype {
		case syscall.SOCK_STREAM, syscall.SOCK_SEQPACKET:
			if err := fd.listenStream(laddr, listenerBacklog(), ctrlFn); err != nil {
				fd.Close()
				return nil, err
			}
			return fd, nil
		case syscall.SOCK_DGRAM:
			if err := fd.listenDatagram(laddr, ctrlFn); err != nil {
				fd.Close()
				return nil, err
			}
			return fd, nil
		}
	}

       所以我们在取数据的时候,应该商定好数据报的长度,或者用一个大的byte数组去接,然后截取。而不应该想tcp那种使用循环去接。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章