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那種使用循環去接。

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