首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python 学习手册
Python Cookbook
Python 基础教程
Python Sites
PyPI - Python Package Index
http://www.simple-is-better.com/
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
V2EX  ›  Python

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

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


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

    我试着还原你的问题。client 发送 32k 数据,server 收取 24k 数据,并没有任何异常发生。
        18
    skinny   46 天前
    @BingoXuan 你没有理解我的意思。
        19
    sujin190   45 天前
    @BingoXuan #17 他的意思的是单个 UDP 包,UDP 没有重排,所以应该是一次必须把整个 UDP 包都接收了,不能分成两次读取一个 UDP 包,跨 UDP 包当然不会有问题了
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   2300 人在线   最高记录 5043   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 24ms · UTC 15:29 · PVG 23:29 · LAX 08:29 · JFK 11:29
    ♥ Do have faith in what you're doing.