Missing asyncio feature regarding support of SCTP sockets
還沒有人認領這個 Issue。
評估
- 難度
- 4/5
- 預估耗時
- 3-5 天
- 新手友好度
- 35/100
- Issue 類型
- 功能
- 描述清晰度
- 基本清楚
- 活躍度
- 停滯
- 技術堆疊
- python
- 領域
- networking
研究方向
在安裝了 libsctp 的 Linux 上執行提供的 SCTP 用戶端和伺服器重現,並比較原生 asyncio 與 uvloop。接著檢查 uvloop/handles/tcp.pyx 以及 uvloop/loop.pyx 中的 create_connection 路徑。完成的標準是 SCTP 用戶端和伺服器連線能夠在 uvloop 下運作,且不會出現回報的協定錯誤或連線中斷。
由索引模型根據 Issue 內容生成。
描述
-
uvloop version: v0.16.0
-
Python version: 3.10.4
-
Platform: Linux
Please note that SCTP works only if you have libsctp(-dev) installed on your Linux system. MacOS doesn't support SCTP without further effort and Windows I cannot say, since I don't use WIndows. -
Can you reproduce the bug with
PYTHONASYNCIODEBUGin env?: Please clarify if you expect further output from uvloop in this case. The error is an OS error as a result of uvloop OS socket configuration, so there is no additional output I can see other than the output below. I will edit my post accordingly if I am missing information or should try something else. Thanks! -
Does uvloop behave differently from vanilla asyncio? How?: Yes, in vanilla asyncio, SCTP sockets can be used out of the box, behaving in the same way TCP stream sockets do.
I am using SCTP as the transport stream protocol, which works fine with Python vanilla asyncio. Asyncio shows the same behaviour as for TCP sockets, which is expected since both transport protocols are stream protocols. However, uvloop seems to only allow TCP sockets.
Server side SCTP socket issue observation
When using an SCTP listening server socket, starting the server works fine. As soon as a SCTP client tries to connect, no connection notification or client data ever reaches the Python application code, but also no errors or other messages are observed on application layer. Wireshark shows that the connection from the client is dropped by the server side right after the SCTP cookie ack handshake.
Client side SCTP socket issue observation
Using an SCTP socket for a client raises an OS Error. From the stack trace it looks like uvloop is trying to use TCP under the hood instead of the SCTP socket.
Traceback (most recent call last):
File "/home/lukas/uvloop-bug-report/client.py", line 69, in <module>
asyncio.run(start_client(use_sctp=True))
File "/usr/lib/python3.10/asyncio/runners.py", line 44, in run
return loop.run_until_complete(main)
File "uvloop/loop.pyx", line 1501, in uvloop.loop.Loop.run_until_complete
File "/home/lukas/uvloop-bug-report/client.py", line 55, in start_client
transport, _ = await asyncio.get_event_loop().create_connection(
File "uvloop/loop.pyx", line 2057, in create_connection
File "uvloop/loop.pyx", line 2045, in uvloop.loop.Loop.create_connection
File "uvloop/handles/tcp.pyx", line 177, in uvloop.loop.TCPTransport._open
File "uvloop/handles/tcp.pyx", line 34, in uvloop.loop.__tcp_open
OSError: [Errno 92] Protocol not available
To reproduce the issues, the following client/server code can be used on a Linux machine or wrapped in a Linux based Docker container if you don't have a Linux OS (I am happy to help with this if needed).
Server code
"""
The server side of the asyncio/uvloop SCTP socket demo.
Author: Lukas Stermann <lukas@ng-voice.com>
"""
import asyncio
import socket
from typing import Optional
import uvloop
class ServerProtocol(asyncio.Protocol):
"""
This is just a dummy server echo protocol for demo purposes.
"""
def __init__(self):
self.transport: Optional[asyncio.Transport] = None
def connection_made(self, transport: asyncio.Transport) -> None:
self.transport = transport
print('New connection from client')
def data_received(self, raw_data: bytes) -> None:
print(f'Data received from client: <{raw_data.decode()}>')
self.transport.write(b'pong')
def connection_lost(self, exc: Optional[Exception]) -> None:
print('Connection lost')
self.transport.close()
async def start_server(use_sctp: bool = True) -> None:
"""
This server starts a listening TCP/SCTP socket.
:param use_sctp: Whether the server shall use SCTP.
If set to False it uses TCP.
"""
socket_: socket.socket
if use_sctp:
socket_ = socket.socket(socket.AF_INET6,
socket.SOCK_STREAM,
socket.IPPROTO_SCTP)
else:
socket_ = socket.socket(socket.AF_INET6,
socket.SOCK_STREAM)
socket_.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
if socket.has_dualstack_ipv6():
socket_.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)
else:
print('This OS does not support IPv4/IPv6 dual stack. '
'Falling back to IPv6 only.')
socket_.setblocking(False)
socket_.bind(('', 10002))
socket_.listen()
connection_settings: dict = {
'protocol_factory': lambda: ServerProtocol(),
'sock': socket_}
server = await asyncio.get_event_loop().create_server(**connection_settings)
await server.serve_forever()
# Comment in the following line to see the issue with using an SCTP socket in uvloop.
# None of the print statements in the protocol are executed and the socket is closed
# right after the SCTP cookie handshake (use Wireshark to see this behaviour or see attached pcap).
uvloop.install()
# Switch between TCP and SCTP to see that for uvloop TCP works well, while SCTP doesn't
asyncio.run(start_server(use_sctp=True))
Client code
"""
The client side of the asyncio/uvloop SCTP socket demo.
Author: Lukas Stermann <lukas@ng-voice.com>
"""
import asyncio
import socket
from typing import Optional
import uvloop
class ClientProtocol(asyncio.Protocol):
"""
This is just a dummy client echo protocol for demo purposes.
"""
def __init__(self):
self.transport: Optional[asyncio.Transport] = None
def connection_made(self, transport: asyncio.Transport) -> None:
self.transport = transport
print('Connection established to server')
self.transport.write(b'ping')
def data_received(self, raw_data: bytes) -> None:
print(f'Answer received from server: <{raw_data.decode()}>')
def connection_lost(self, exc: Optional[Exception]) -> None:
print('Connection lost')
self.transport.close()
async def start_client(use_sctp: bool = True) -> None:
"""
This client sends a message over TCP/SCTP socket.
:param use_sctp: Whether the server shall use SCTP.
If set to False it uses TCP.
"""
connection_parameters: dict = {
'protocol_factory': lambda: ClientProtocol()
}
if use_sctp:
socket_ = socket.socket(socket.AF_INET, socket.SOCK_STREAM,
socket.IPPROTO_SCTP)
else:
socket_ = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket_.setblocking(False)
connection_parameters['sock'] = socket_
await asyncio.get_event_loop().sock_connect(
socket_, ('127.0.0.1', 10002))
transport, _ = await asyncio.get_event_loop().create_connection(
**connection_parameters)
await asyncio.sleep(2)
transport.close()
# Comment in the following line to see the issue with using an SCTP socket in uvloop.
# The client will crash with OSError saying the protocol is not supported
uvloop.install()
# Switch between TCP and SCTP to see that for uvloop TCP works well, while SCTP doesn't
asyncio.run(start_client(use_sctp=True))
Please also find attached a zipped PCAP for Wireshark. The first part of the trace there is the vanilla asyncio version with the uvloop.install() command commented out in both client and server code. The second trace shows the behavior when the server is using uvloop but the client is using vanilla asyncio.
Would be great if you would comment on this, cheers for your work, really appreciate that you are bringing performance to Python :)
- 主要語言
- Cython
- 星號
- 11.9k
- 分支
- 615
- PR 合併指標
- 30 天內沒有已合併 PR
貢獻指南
這個儲存庫沒有索引到貢獻指南
從這裡開始
- 先讀完整個 Issue,再讀專案的貢獻指南。
- 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
- Fork 儲存庫,在一個分支上完成修改。
- 送出 Pull Request,並在描述裡引用這個 Issue 編號。
MagicStack/uvloop 的其他 Issue
-
難度 2/5 1-3 小時 新手友好度 68/100
MagicStack/uvloop#759 ·
-
難度 2/5 1-3 小時 新手友好度 68/100
MagicStack/uvloop#741 · 2 個 reaction ·
-
難度 2/5 1-3 小時 新手友好度 68/100
MagicStack/uvloop#702 · 8 則留言 · 9 個 reaction ·
-
難度 4/5 3-5 天 新手友好度 25/100
MagicStack/uvloop#766 ·
-
難度 4/5 3-5 天 新手友好度 52/100
MagicStack/uvloop#765 ·
查看 MagicStack/uvloop 的全部 Issue
相似的 Issue
-
bug good first issue needs testing
難度 2/5 1-3 小時 新手友好度 75/100
-
難度 2/5 1-3 小時 新手友好度 75/100
TencentCloud/Octop#1093 · 1 則留言 ·
-
Nmap
難度 1/5 1 小時以內 新手友好度 85/100
-
bug
難度 2/5 1-3 小時 新手友好度 70/100
community-scripts/ProxmoxVE#17471 · 2 則留言 ·
-
bug DEV: backend
難度 2/5 1-3 小時 新手友好度 75/100
learningequality/kolibri#15331 ·