UDP 和 TCP 的行为边界到底在哪?这篇用 DatagramChannel 在回环上把数据报边界、大小上限、丢包与 connect 的语义逐项打印出来(TCP 的字节流与粘包拆包见前面的篇目)。
发送 3 个数据报(10、100、1000 字节),接收方用 4096 字节的缓冲区各 receive 一次:
每次收到的字节数 = [10, 100, 1000](一次 send 对应一次 receive,边界保留,不像 TCP 会合并)
发 1000 字节、接收缓冲区只有 100 字节:这次 receive 读到 100 字节,剩下 900 字节被丢弃——再 receive 一次会阻塞(用非阻塞检查):
再次 receive 的结果:没有数据(null),被截断的 900 字节没有留下
发送 0 字节的数据报:接收方收到 position = 0(空数据报是合法的)发送缓冲区(SO_SNDBUF)= 65527,接收缓冲区(SO_RCVBUF)= 786896 send 1400 字节 → 成功,返回 1400 send 8192 字节 → 成功,返回 8192 send 9200 字节 → 成功,返回 9200 send 9216 字节 → 成功,返回 9216 send 9217 字节 → 成功,返回 9217 send 20000 字节 → 成功,返回 20000 send 65000 字节 → 成功,返回 65000 send 65507 字节 → 成功,返回 65507 send 65508 字节 → SocketException: Message too long
SO_RCVBUF 设为 默认(实际 786896):发送方一口气发 100000 个 100 字节的数据报,接收方之后才开始读,收到 4099 个(丢了 95901 个,95.9%);最早的序号 0,最晚的 4098 SO_RCVBUF 设为 1 MB(实际 1048576):发送方一口气发 100000 个 100 字节的数据报,接收方之后才开始读,收到 5462 个(丢了 94538 个,94.5%);最早的序号 0,最晚的 5461 SO_RCVBUF 设为 8 MB(实际 6710884):发送方一口气发 100000 个 100 字节的数据报,接收方之后才开始读,收到 34953 个(丢了 65047 个,65.0%);最早的序号 0,最晚的 34952
未连接的 channel 向没人监听的端口 send:没有任何异常(UDP 不知道对方在不在)
connect 到没人监听的端口之后连续 write:第 2 次 write 抛 PortUnreachableException(对端的 ICMP 端口不可达被转成了异常;只有已连接的 channel 才会)
rx 已 connect 到 good:另一个陌生的发送者先发 {9},good 后发 {1},rx.read 读到的是 1(已连接的 channel 只接收指定对端的数据报,别的被丢弃)