Перейти к основному содержимому

TCP и UDP в Go

Разработчику

См. также: Асинхронность и горутины · Веб на stdlib · Простые приложения.

Уровни сетевого стека

УровеньПакет GoПример
HTTPnet/httpREST, веб-страницы
TCP/UDPnetСокеты, игры, брокеры, кастомные протоколы
IP и нижеnet, syscallРедко в прикладном коде

HTTP поверх TCP уже разбирает заголовки, тело, keep-alive. Ниже — поток байтов без семантики запрос/ответ.


TCP-сервер (echo)

func main() {
ln, err := net.Listen("tcp", ":9000")
if err != nil {
log.Fatal(err)
}
defer ln.Close()

for {
conn, err := ln.Accept()
if err != nil {
log.Print(err)
continue
}
go handleConn(conn) // одна горутина на соединение
}
}

func handleConn(c net.Conn) {
defer c.Close()
io.Copy(c, c) // эхо: всё прочитанное — обратно клиенту
}

net.Conn реализует io.Reader и io.Writer — удобно стыкуется с буферами и протоколами.


TCP-клиент

conn, err := net.Dial("tcp", "localhost:9000")
if err != nil {
log.Fatal(err)
}
defer conn.Close()

_, err = conn.Write([]byte("ping\n"))
buf := make([]byte, 1024)
n, err := conn.Read(buf)

Dial с таймаутом:

d := net.Dialer{Timeout: 5 * time.Second}
conn, err := d.DialContext(ctx, "tcp", host)

UDP

UDP — дейтаграммы без установления сессии:

addr, _ := net.ResolveUDPAddr("udp", ":9001")
conn, _ := net.ListenUDP("udp", addr)
defer conn.Close()

buf := make([]byte, 65507) // макс. размер UDP payload
n, remote, err := conn.ReadFromUDP(buf)
_, err = conn.WriteToUDP(buf[:n], remote)

Клиент: net.Dial("udp", "host:9001") или ListenUDP только на стороне сервера.

Подходит для DNS-подобных запросов, телеметрии, игр; порядок и доставка не гарантированы — это закладывают в протокол.


Буферизация и протокол

Сырые Read могут вернуть часть сообщения. Для текстовых протоколов — bufio.Scanner или bufio.Reader.ReadString('\n'). Для бинарных — длина кадра в заголовке (4 байта LE + payload).

scanner := bufio.NewScanner(conn)
for scanner.Scan() {
line := scanner.Text()
// обработка строки
}

Установите scanner.Buffer и MaxScanTokenSize, если строки длинные.


Связь с горутинами

Паттерн «одно TCP-соединение — одна горутина» масштабируется на тысячи клиентов за счёт лёгких горутин (асинхронность). Блокирующий Read в горутине не блокирует весь сервер.

Ограничение нагрузки: семафор, net.Listen с лимитом через обёртку, или пул воркеров с очередью соединений.


TLS поверх TCP

tls.Listen / tls.Dial оборачивают TCP шифрованием. HTTP-сервер с TLS обычно настраивают через http.Server и ListenAndServeTLS, а не вручную на сыром сокете.


HTTP и сырой сокет

Критерийnet/httpnet TCP/UDP
ФорматЗапрос/ответ, заголовкиСвой протокол
ИнструментыMiddleware, JSON, шаблоныПолный контроль
Типичное применениеAPI, сайтыИгры, VPN-части, агенты

Для обучения достаточно echo-сервера; для продакшена API чаще выбирают HTTP (веб на stdlib или фреймворки).


См. также

Другие статьи этого же раздела в боковом меню (как на странице «О разделе»).