python / python/cpython

`asyncio` does not set `TCP_NODELAY` on macOS

未關閉
#148,783 0 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視

還沒有人認領這個 Issue。

stdlib type-bug
主要語言
Python
星號
77.2k
分支
35.9k
PR 合併指標
PR 指標待擷取

描述

Bug report

Bug description:

On macOS, asyncio server silently skips setting TCP_NODELAY on accepted connections.

Reproduce
import asyncio
import socket

async def main():
    async def on_connect(reader, writer):
        sock = writer.transport.get_extra_info('socket')
        nodelay = sock.getsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY)
        print(f'server side: sock.proto={sock.proto} TCP_NODELAY={nodelay}')
        writer.close()
        await writer.wait_closed()
        srv.close()

    srv = await asyncio.start_server(on_connect, '127.0.0.1', 0)
    port = srv.sockets[0].getsockname()[1]

    reader, writer = await asyncio.open_connection('127.0.0.1', port)
    sock = writer.transport.get_extra_info('socket')
    nodelay = sock.getsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY)
    print(f'client side: sock.proto={sock.proto} TCP_NODELAY={nodelay}')

    await asyncio.sleep(0.1)
    writer.close()
    await writer.wait_closed()
    await srv.wait_closed()

asyncio.run(main())
Platform Side sock.proto TCP_NODELAY
Linux client 6 ✅ 1 ✅
Linux server 6 ✅ 1 ✅
macOS client 6 ✅ 4 ✅
macOS server 0 ❌ 0 ❌

Cause

In socket.__init__, CPython tries to detect proto with getsockopt + SO_PROTOCOL and falls back to 0 if SO_PROTOCOL is not supported, which is the case on macOS.

https://github.com/python/cpython/blob/82767780f8de2fc492567ceb6a590101ae3b19ad/Modules/socketmodule.c#L5749-L5764

While socket.accept does pass in the proto from listening socket, it is silently overridden to zero by the above logic.

https://github.com/python/cpython/blob/82767780f8de2fc492567ceb6a590101ae3b19ad/Lib/socket.py#L300

asyncio sets TCP_NODELAY only when sock.proto == socket.IPPROTO_TCP, but it is 0 on macOS for the above reason.

https://github.com/python/cpython/blob/82767780f8de2fc492567ceb6a590101ae3b19ad/Lib/asyncio/base_events.py#L193-L201

Client socket works fine because no fd is passed to socket.__init__ so the proto detection doesn't happen.

CPython versions tested on:

3.13

Operating systems tested on:

macOS, Linux

Linked PRs
  • gh-148784

貢獻指南

開啟貢獻指南

從這裡開始

  1. 先讀完整個 Issue,再讀專案的貢獻指南。
  2. 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
  3. Fork 儲存庫,在一個分支上完成修改。
  4. 送出 Pull Request,並在描述裡引用這個 Issue 編號。

研究方向

檢查 Modules/socketmodule.c、Lib/socket.py 和 Lib/asyncio/base_events.py 中連結的實作,從 socket.init 和 socket.accept 開始。在開始之前檢查 PR gh-148784;完成的標準是,macOS 接受的連線能夠收到預期的 TCP 通訊協定資訊,且 asyncio 與用戶端連線一致地設定 TCP_NODELAY。

由索引模型根據 Issue 內容生成。

評估

技術堆疊
c, python
領域
networking
Issue 類型
缺陷
難度
4/5
預估耗時
3-5 天
活躍度
停滯
描述清晰度
描述清楚
新手友好度
25/100

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。