В каком формате передаются данные по сети
Что проверяют
Вопрос нарочно размытый: интервьюер смотрит, начнёте ли вы с того, что по сети идут байты, и различаете ли уровень транспорта и формат сериализации. Следом обычно спрашивают, как в TCP понять, где кончается одно сообщение, и чем Protobuf лучше JSON.
Как отвечать
Разложите ответ по уровням:
- транспорт: по сети идёт последовательность байтов. TCP это поток без границ сообщений, UDP передаёт отдельные датаграммы. Многобайтовые числа в заголовках протоколов пишутся в сетевом порядке, big-endian, в Go для этого есть
encoding/binaryиbinary.BigEndian; - прикладной протокол: HTTP/1.1 передаёт текстовые заголовки, HTTP/2 и HTTP/3 режут данные на бинарные фреймы;
- формат сериализации: то, что лежит в теле сообщения.
Форматы с привязкой к Go:
- JSON:
encoding/json, теги структур вродеjson:"name,omitempty". Читаемый, но медленнее бинарных форматов и работает через рефлексию; - Protocol Buffers:
google.golang.org/protobuf, код генерируется из.protoчерезprotoc. Компактный бинарный формат со схемой, основа gRPC; - MessagePack, CBOR: бинарные аналоги JSON без обязательной схемы;
encoding/gob: родной формат Go, удобен между Go-сервисами, но другие языки его не понимают;- XML:
encoding/xml, живёт в интеграциях с SOAP и старыми банковскими системами.
Для своего протокола поверх TCP нужен фрейминг: префикс длины (часто 4 байта) перед сообщением или разделитель. В Go это io.ReadFull для чтения точного числа байтов или bufio.Scanner для построчного формата.
Где спотыкаются
Отвечают одним словом «JSON» и не видят, что вопрос шире. Транспорт и сериализацию стоит развести с первых фраз.
Считают, что один вызов conn.Read() возвращает одно сообщение. TCP может склеить два сообщения или порезать одно на части, и без фрейминга парсер ломается под нагрузкой.
Меняют номера полей в .proto или переиспользуют номер удалённого поля. Старые клиенты начинают читать чужие данные, поэтому удалённые номера помечают reserved.