UDP 网络编程时,在 recvfrom 出现缓冲区过小错误时,有没有办法获得发送这个大数据报的客户端的源地址(IP, PORT)?

2019-08-31 16:16:20 +08:00
 skinny
在原始的 IP 和 UDP 数据包里有这个地址信息,可是 Python socket API 遇到缓冲区过小是直接抛异常,但是异常信息里却不提供这个源地址信息,还有,C SOCKET API 是提供这个信息的。
2548 次点击
所在节点    Python
19 条回复
Cyshall
2019-08-31 16:43:52 +08:00
recvfrom()这个 syscall 最后两个参数就是发送方的地址信息阿。
skinny
2019-08-31 17:05:38 +08:00
@Cyshall 那个是成功的时候才有啊。比如 server_sock.recvfrom(64),client 发送的数据报大小小于或等于 64,一切正常,返回(data, address),可如果对方发送了 65 个字节,server_sock.recvfrom(64)就会抛 OSError,也就获取不到了,OSError 实例里也没有这个信息。
skinny
2019-08-31 17:08:44 +08:00
如果非要 hack 底层或写一大坨 ctypes 代码才能获取,那我就放弃算了……
skinny
2019-08-31 17:44:23 +08:00
看了下 CPython socket 模块的 C 代码,没希望了……要么换语言,要么改一坨代码。
lcdtyph
2019-08-31 18:01:47 +08:00
试一下 MSG_TRUNC 这个 flag ?
fengtons
2019-08-31 18:02:13 +08:00
试一下 recvmsg 看行不行
elfive
2019-08-31 18:15:44 +08:00
一般 UDP 包大小以不超过 MTU 为最佳,所以我一般缓冲区会根据网络类型设定不同的缓冲区大小
BingoXuan
2019-08-31 19:02:24 +08:00
udp 是一个一个的消息,一般都会 recv 大小是 mtu 值。如果是 tcp 流,你可以源源不断地 recv。
skinny
2019-08-31 20:13:57 +08:00
@elfive
@BingoXuan
正常情况下来说是这样,可是你如果写一个 UDP Server,也许有恶意的或者有 BUG 的程序,发来一堆这种大于预先协商好大小的缓冲区的数据报,而你却因为这种问题导致无法记录有效数据……还是不用 Python 写 UDP Server 了。


@lcdtyph
@fengtons
这两个都是 Unix/Linux 才有的,而且不符合需求。
aguesuka
2019-09-01 00:47:39 +08:00
用 noi,超过 buff 的数据会被丢弃
aguesuka
2019-09-01 00:49:13 +08:00
没看到是 python
elfive
2019-09-01 06:40:44 +08:00
@skinny #9 Python 抛异常其实也算能理解,毕竟 udp socket 在调用 recvfrom()以后会清空内核中对应 udp 端口的接收缓冲区,Python 可能认为收到不完整的内容就是一种异常,所以需要你特别注意,你就封装一下,用 try...catch 捕获处理这个异常就好了。这一点,所有 udp socket 其实都一样。只是有些库或语言帮你处理了,有些则没有而已。
skinny
2019-09-01 07:59:49 +08:00
@elfive 严肃的说,对于 UDP Server,最好还是是使用一个 64K 的大接收缓冲区,反正无论对面怎么样都发不了大于这个的数据报,接收后交给 Handler 检查处理以及记录,所以主楼的问题就是我有点钻牛角尖了,只是不爽 Python 就只是抛异常,却不告诉我异常是哪个源地址造成的。
elfive
2019-09-01 08:31:25 +08:00
@skinny #13 直接分配 64K,确实是最稳妥暴力的解决方法。但如果真的有这种大小的数据过来,正常的用户通讯肯定会受到不小影响。有点类似 DDOS 的感觉了
skinny
2019-09-01 10:08:48 +08:00
@elfive 正儿八经的 UDP Server 应用肯定不能拿 Python 这样写了,我是写一个 Python 网络服务测试工具时需要一个加密代理(你懂的……),却没有找到合适趁手简单好用的库,所以临时自己写一个简单一点的。
dazhangpan
2019-09-01 15:10:42 +08:00
目测用 kprobe + ftrace 可行
在内核收取的方法里看
BingoXuan
2019-09-01 18:05:25 +08:00
@skinny
我觉得你这种就有点炜疾忌医的感觉。不合理数据导致异常完全可以丢弃,但没必要说什么语言不合适。很多时候这些问题遇到概率实在太小了。只要在异常处理时候,处理一下就好了

我试着还原你的问题。client 发送 32k 数据,server 收取 24k 数据,并没有任何异常发生。
skinny
2019-09-01 20:34:39 +08:00
@BingoXuan 你没有理解我的意思。
sujin190
2019-09-02 17:33:11 +08:00
@BingoXuan #17 他的意思的是单个 UDP 包,UDP 没有重排,所以应该是一次必须把整个 UDP 包都接收了,不能分成两次读取一个 UDP 包,跨 UDP 包当然不会有问题了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/596765

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX