很多初學者嘗試用 socket.SOCK_RAW 手工構造 TCP 數據包,結果發現極其複雜:需手動填寫 IP 頭、TCP 頭、校驗和、處理分片重組、三次握手狀態機……
# 錯誤示範:以為這樣就是發 TCP
sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_TCP)
sock.sendto(packet_base, 0, (IP_PACKET_IN, 12321))
SOCK_RAW + IPPROTO_TCP 意味著你負責完整構造 IP+TCP 頭部,內核不會幫你做三次握手、序列號管理、重傳、流控。這是防火牆/掃描器開發者的工作,不是應用層發數據的正規途徑。
# 正確示範:內核自動處理 TCP 協議細節
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # TCP 流式套接字
sock.connect(("目標IP", 目標端口))
sock.sendall(b"你的應用層數據") # 直接發應用層 payload
sock.close()
sendall 發送的字節流會被內核封裝為 TCP 段(Segment),TCP 頭部的 Payload 就是你的數據。生產環境建議使用 asyncio、selectors 或 Twisted/asyncio.streams 實現非阻塞 I/O,單線程處理萬級連接。