Прием UDP-пакета в Go
Слушатель сначала привязывается к локальному порту на выбранном интерфейсе. Для учебных примеров хватит строки с петлевым адресом и номером порта, который не занят другой программой.
Чтение из сокета возвращает три результата: сколько байт попало в буфер, откуда пришел пакет и была ли ошибка. Буфер задают фиксированной длиной; если сообщение длиннее, лишнее отрежется, остальное нужно читать следующим вызовом.
Привяжемся к "127.0.0.1:9091"
и дождемся одного пакета:
package main
import (
"fmt"
"net"
)
func main() {
addr, err := net.ResolveUDPAddr("udp", "127.0.0.1:9091")
if err != nil {
fmt.Println("resolve error")
return
}
conn, err := net.ListenUDP("udp", addr)
if err != nil {
fmt.Println("listen error")
return
}
defer conn.Close()
buf := make([]byte, 1024)
n, remote, err := conn.ReadFromUDP(buf)
if err != nil {
fmt.Println("read error")
return
}
fmt.Println(string(buf[:n]), remote.String())
}
Программа ждет, пока кто-то не пошлет данные на этот порт. Вторая строка вывода покажет адрес отправителя в том виде, как его вернула библиотека.
Тот же прием удобно вынести в цикл, если служба должна обрабатывать много пакетов подряд:
package main
import (
"fmt"
"net"
)
func main() {
addr, _ := net.ResolveUDPAddr("udp", "127.0.0.1:9091")
conn, err := net.ListenUDP("udp", addr)
if err != nil {
fmt.Println("listen error")
return
}
defer conn.Close()
buf := make([]byte, 512)
for i := 0; i < 2; i++ {
n, remote, err := conn.ReadFromUDP(buf)
if err != nil {
fmt.Println("read error")
return
}
fmt.Println(i, string(buf[:n]), remote.IP)
}
}
Дан адрес:
local := "127.0.0.1:9091"
Откройте прием на local, прочитайте
один пакет в буфер на 256 байт
и выведите текст и IP отправителя.
Дан фрагмент после успешного чтения:
n, remote, err := conn.ReadFromUDP(buf)
text := string(buf[:n])
Скажите, зачем для text берут срез
buf длиной n, а не весь
буфер целиком.
Скажите, что произойдет со вторым и третьим пакетом, если первый вызов чтения уже забрал данные, а цикл чтения еще не запущен.