网络编程基础:Socket编程入门、Python的socket模块、建立TCP连接
做量化交易,说白了就是跟数据打交道。而数据怎么来的?通过网络。网络怎么连?靠Socket。
我记得刚入行那会儿,总觉得Socket是底层的东西,跟我做策略没啥关系。直到有一次,我写的行情接收程序莫名其妙断连,数据丢了整整三分钟……嗯,那三分钟让我明白了一个道理:不懂Socket,你连数据都拿不稳。
Socket是什么?别想复杂了
Socket,中文叫「套接字」。名字挺唬人,其实没那么玄乎。
你可以把它想象成两个程序之间的电话线。一端是你的程序,另一端是交易所的服务器。你拨号(连接),对方接听(accept),然后你们开始通话(收发数据)。挂断(close),通话结束。
在量化场景里,这条电话线就是用来传输行情数据的。每秒几万笔的订单簿、逐笔成交、K线……全得靠它。
核心要点:Socket是操作系统提供的网络通信接口。你不需要管底层怎么封装TCP/IP包,只需要调用几个函数,就能完成网络通信。
TCP vs UDP:量化场景怎么选?
Socket编程主要分两种:TCP和UDP。我直接说结论——
| 特性 | TCP | UDP |
|---|---|---|
| 连接方式 | 面向连接(先握手) | 无连接(直接发) |
| 可靠性 | 保证送达,顺序不乱 | 可能丢包,顺序可能乱 |
| 速度 | 相对慢(有确认机制) | 快(只管发不管到) |
| 典型场景 | 行情订阅、交易下单 | 极速行情(如L1快照) |
我个人习惯:做行情解码,90%的情况用TCP。为什么?因为行情数据不能丢。你想想看,如果丢了一笔成交数据,你的策略可能就会做出错误判断。UDP虽然快,但丢包了没人通知你,这是大忌。
我的经验:有些交易所提供UDP行情,但通常会搭配一个「补数据」机制。如果你刚开始学,先玩转TCP再说。TCP稳,容错高,适合入门。
Python的socket模块:三板斧搞定
Python自带的socket模块,封装得相当优雅。你不需要写C语言的繁琐代码,几行就能建一个连接。
核心就三个步骤:
- 创建Socket对象 —— 选TCP还是UDP
- 连接服务器 —— 指定IP和端口
- 收发数据 —— recv/send
来,直接看代码:
import socket
# 第一步:创建TCP Socket
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 第二步:连接服务器(以某行情服务器为例)
server_addr = ('192.168.1.100', 8888)
client.connect(server_addr)
# 第三步:接收数据(假设服务器会主动推送)
data = client.recv(4096) # 一次最多收4096字节
print(f"收到数据:{data.hex()}") # 行情数据通常是二进制
# 用完记得关
client.close()
是不是很简单?但别高兴太早——实际生产环境远没这么简单。
避坑指南:我曾经踩过的三个坑
代码看着简单,真跑起来问题一堆。我一个个说:
坑一:recv不一定能一次收完
我曾经以为recv(4096)就能收到完整的一帧行情数据。结果呢?行情数据包可能只有100字节,也可能有5000字节。recv返回的数据长度是不确定的。你必须自己处理「粘包」问题。
解决方案:先约定好数据帧的长度,或者用固定长度的消息头。
坑二:连接会断
网络波动、服务器重启、防火墙超时……连接随时可能断开。我见过最离谱的一次,交易所的网关凌晨3点重启,我的程序直接卡死在recv上,直到第二天开盘才发现。
解决方案:加心跳检测,设置超时时间,断线自动重连。
坑三:阻塞与非阻塞
默认的recv是阻塞的——没数据就卡住。如果你的程序还要做其他事情(比如计算指标),那就麻烦了。
解决方案:用settimeout设置超时,或者用非阻塞模式+select/poll。
建立TCP连接的完整流程
咱们把上面的代码完善一下,加一些实战中必须的东西:
import socket
import time
def connect_with_retry(host, port, max_retries=3):
"""
带重试机制的TCP连接
我在项目中用过无数次了,稳
"""
for i in range(max_retries):
try:
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.settimeout(5) # 5秒超时
client.connect((host, port))
print(f"连接成功!第{i+1}次尝试")
return client
except Exception as e:
print(f"连接失败:{e},等待重试...")
time.sleep(2 ** i) # 指数退避
raise Exception("重试次数耗尽,连接失败")
# 使用示例
client = connect_with_retry('192.168.1.100', 8888)
# 循环接收数据
buffer = b''
while True:
try:
chunk = client.recv(4096)
if not chunk:
print("连接已断开")
break
buffer += chunk
# 这里可以解析数据帧
# 比如:如果buffer长度足够,就解析一帧
except socket.timeout:
print("接收超时,但连接还在")
continue
except Exception as e:
print(f"接收异常:{e}")
break
client.close()
小技巧:指数退避重试是个好东西。第一次失败等2秒,第二次等4秒,第三次等8秒。既不会把服务器打爆,又能快速恢复连接。
本章知识体系:一张图看懂
下面这张SVG图,把Socket编程的核心逻辑串起来了。你照着这个思路学,不会乱。
这张图把本章内容分成了三大块:Socket基础、TCP连接、数据收发。每一块都有对应的实战要点。你照着这个框架去学,思路会清晰很多。
小结
Socket编程是量化交易数据处理的第一道门槛。跨过去,后面的路就好走了。
我个人建议:别光看,动手敲一遍上面的代码。把IP换成你本地的127.0.0.1,端口随便选一个(比如9999),自己写一个服务端和客户端,跑通再说。
嗯,下一节我们会深入粘包处理和高性能IO模型。但今天先把TCP连接练熟,这是地基。
公众号:蓝海资料掘金营,微信deep3321