网络编程基础: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语言的繁琐代码,几行就能建一个连接。

核心就三个步骤:

  1. 创建Socket对象 —— 选TCP还是UDP
  2. 连接服务器 —— 指定IP和端口
  3. 收发数据 —— 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编程核心知识体系 Socket基础 AF_INET / SOCK_STREAM TCP连接 connect / bind / listen 数据收发 send / recv / close IPv4 vs IPv6 TCP vs UDP 选择 三次握手原理 重试与超时机制 粘包处理 阻塞 vs 非阻塞 实战要点:心跳检测 + 断线重连 指数退避重试 / 超时设置 / 缓冲区管理 量化交易场景下,TCP + 重连机制是最稳妥的选择

这张图把本章内容分成了三大块:Socket基础TCP连接数据收发。每一块都有对应的实战要点。你照着这个框架去学,思路会清晰很多。

小结

Socket编程是量化交易数据处理的第一道门槛。跨过去,后面的路就好走了。

我个人建议:别光看,动手敲一遍上面的代码。把IP换成你本地的127.0.0.1,端口随便选一个(比如9999),自己写一个服务端和客户端,跑通再说。

嗯,下一节我们会深入粘包处理高性能IO模型。但今天先把TCP连接练熟,这是地基。


公众号:蓝海资料掘金营,微信deep3321