Пакет net встроенных функций и типов языка Go

Пакет net предоставляет переносимый интерфейс для сетевого ввода-вывода, включая TCP/IP, UDP, разрешение доменных имен и сокеты доменов Unix.

Пакет обеспечивает доступ к примитивам низкоуровневых сетей, большинству клиентов понадобится только базовый интерфейс, предоставляемый функциями Dial, Listen и Accept и связанными интерфейсами Conn и Listener. Пакет crypto/tls использует те же интерфейсы и похожие функции Dial и Listen.

Функция Dial подключается к серверу:

conn, err := net.Dial("tcp", "golang.org:80")
if err != nil {
	// handle error
}
fmt.Fprintf(conn, "GET / HTTP/1.0\r\n\r\n")
status, err := bufio.NewReader(conn).ReadString('\n')
// ...

Функция Listen создает серверы:

ln, err := net.Listen("tcp", ":8080")
if err != nil {
	// handle error
}
for {
	conn, err := ln.Accept()
	if err != nil {
		// handle error
	}
	go handleConnection(conn)
}

Разрешение имен (Name Resolution)

Метод разрешения доменных имен (DNS) в пакете net зависит от операционной системы. Функции, такие как Dial, используют разрешение имен косвенно, а функции вроде LookupHost и LookupAddr делают это напрямую.

На Unix-системах

Ресолвер имеет два варианта работы:

  1. Чистый Go-ресолвер – отправляет DNS-запросы напрямую к серверам, указанным в /etc/resolv.conf.
  2. CGO-ресолвер – использует системные вызовы C (getaddrinfo, getnameinfo).

Чистый Go-ресолвер предпочтительнее, потому что:

  • Заблокированный DNS-запрос потребляет только горутину (легковесный поток Go).
  • Заблокированный вызов C занимает системный поток ОС (более затратно).

Когда используется CGO-ресолвер?

  • На системах, где запрещены прямые DNS-запросы (например, macOS).
  • Если заданы переменные окружения:
    • LOCALDOMAIN (даже пустая),
    • RES_OPTIONS,
    • HOSTALIASES (не пустые),
    • ASR_CONFIG (только OpenBSD).
  • Если /etc/resolv.conf или /etc/nsswitch.conf требуют функциональности, не реализованной в Go.

Лимит на CGO-запросы
Во всех системах (кроме Plan 9) действует ограничение в 500 одновременных CGO-запросов, чтобы избежать исчерпания системных потоков.


Управление выбором ресолвера

Можно переопределить выбор ресолвера через переменную окружения GODEBUG:

export GODEBUG=netdns=go    # принудительно использовать чистый Go-ресолвер
export GODEBUG=netdns=cgo   # принудительно использовать нативный (CGO) ресолвер

Также можно задать поведение при сборке через теги:

  • netgoтолько Go-ресолвер (CGO полностью отключен).
  • netcgo – оба ресолвера, но CGO имеет приоритет (можно переопределить через GODEBUG=netdns=go).

Отладочная информация
Если установить GODEBUG=netdns=1, ресолвер будет выводить отладочную информацию. Можно комбинировать:

export GODEBUG=netdns=go+1  # принудительно Go + отладка

EDNS0 и проблемы с роутерами
Go-ресолвер по умолчанию отправляет EDNS0-заголовок, чтобы запрашивать большие DNS-пакеты. Это может вызывать ошибки на некоторых модемах/роутерах. Отключить:

export GODEBUG=netedns0=0

Особенности на разных ОС

  • macOS:
    • Если Go-код собран с -buildmode=c-archive, для линковки в C-программу требуется флаг -lresolv.
  • Plan 9:
    • Ресолвер всегда использует /net/cs и /net/dns.
  • Windows (Go 1.18.x и старше):
    • Всегда используются C-функции (GetAddrInfo, DnsQuery).

Ключевые термины

  • Ресолвер (Resolver) – механизм преобразования доменных имен в IP-адреса.
  • CGO – вызовы C-кода из Go.
  • EDNS0 – расширение DNS, позволяющее увеличить размер пакета.
  • GODEBUG – переменная окружения для настройки поведения Go-рантайма.