明确通信目标,别让协议变成黑话
设计应用层协议前,先想清楚要解决什么问题。比如你要做一个智能家居系统,手机App要控制灯泡开关,那协议就得让人和设备都能看懂“开”和“关”。如果一上来就堆加密、压缩、序列化,最后连自己都看不懂报文长什么样,调试起来就像破案。
很多人喜欢直接抄HTTP或者MQTT的结构,但不是每个场景都需要Header加Body再套一层JSON。简单场景用纯文本指令反而更直观,比如发送POWER ON比构造一个带版本号、序列号、校验码的二进制包来得实在。
保持可读性,日志里别全是乱码
线上出问题时,运维第一反应是看日志。如果你的协议全是字节流,没人愿意一个个算十六进制。不妨在设计时留条后路——比如支持明文模式,或者用JSON封装关键操作。这样查问题不用翻协议文档对照表,省下的是半夜被叫醒的时间。
{"cmd": "light", "action": "toggle", "device_id": 1001, "timestamp": 1712345678}这种格式虽然多花几个字节,但在路由器、IoT网关这类资源不那么紧张的地方完全能接受。
版本控制不能省,老设备也得活下去
产品上线后总会改需求。今天加个亮度调节,明天加个定时任务。如果协议不做版本管理,新客户端发个带brightness字段的请求,老设备可能直接崩溃。建议每个消息头里带上版本号,接收方根据版本决定如何解析。
{"version": 1, "cmd": "set_color", "r": 255, "g": 0, "b": 0}后续升级到v2支持HSV模式,老设备收到不认识的version可以直接拒绝,而不是乱解析导致彩灯变呼吸机。
错误反馈要具体,别只说“失败了”
用户点击按钮没反应,后台日志只记一句“操作失败”,这等于没记。协议里应该定义清晰的错误码,比如4001表示设备离线,4002表示参数超范围。前端可以根据错误码提示“灯还没连上Wi-Fi”还是“你选的亮度值太大了”。
就像快递物流,不能只告诉你“包裹异常”,得说清楚是“拒收”还是“地址不详”。
别把所有逻辑压在协议上
有人总想让协议自己搞定一切:自动重试、流量控制、心跳保活……结果协议越来越重,改一处全链路都要动。其实这些可以交给下层处理。TCP已经能保证可靠传输,再在应用层做确认应答就是重复造轮子。
协议的核心是表达意图,不是实现机制。就像写短信,你说“晚上七点吃饭?”就够了,不用附带“若5分钟内未读则重发,最多3次”这样的说明。