4、网络编程基础:Socket编程入门、TCP与UDP在交易中的选择、非阻塞I/O与epoll模型
做量化交易系统,尤其是高频做市,网络编程是绕不开的坎。说白了,你的策略再牛,如果网络层拉胯,订单发不出去或者收不到行情,一切都是白搭。今天我们就来聊聊网络编程里最核心的几个东西。
Socket编程入门:交易员和交易所的“电话线”
Socket,翻译过来叫“套接字”,但我觉得叫它“通信管道”更形象。你想想看,你的交易程序和交易所服务器之间要说话,总得有个通道吧?Socket就是这个通道的两端。
我刚开始写交易程序时,觉得Socket很神秘。后来发现,它其实就是一套API。你调用它,就能在网络上发数据。核心流程就四步:
- 创建Socket:就像申请一根电话线。
- 绑定地址:告诉系统,我这根线接在哪个端口上。
- 监听/连接:服务端等着别人打进来,客户端主动拨号。
- 收发数据:开始通话,传订单和行情。
一个最简单的TCP客户端代码长这样:
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
int main() {
int sock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(8080);
addr.sin_addr.s_addr = inet_addr("192.168.1.100");
connect(sock, (struct sockaddr*)&addr, sizeof(addr));
// 发送订单
char order[] = "BUY 100 AAPL @ 150.00";
send(sock, order, strlen(order), 0);
return 0;
}
嗯,这里要注意,htons和inet_addr这些函数,是网络编程的“基本功”。我见过不少新手直接写死端口号,结果换了台机器就崩了。建议你把这些配置抽出来,放到配置文件里。
TCP与UDP在交易中的选择:一个都不能少
很多新手会问:“做交易到底用TCP还是UDP?”我的答案是:看场景,而且往往是两者都用。
| 特性 | TCP | UDP |
|---|---|---|
| 可靠性 | 保证送达,顺序一致 | 不保证,可能丢包 |
| 速度 | 较慢(有重传机制) | 极快(无握手) |
| 适用场景 | 订单发送、风控指令 | 行情推送、心跳检测 |
我个人习惯是:订单走TCP,行情走UDP。为什么?
- 订单必须可靠:你下了一笔买单,如果丢了,可能就错过了最佳成交价。TCP的重传机制虽然慢一点,但能保证交易所一定收到。
- 行情可以容忍丢包:行情数据每秒成千上万笔,丢了一两笔,下一笔马上补上。UDP的延迟更低,更适合做市商抢速度。
我在项目中遇到过一个问题:某次用UDP推行情,结果网络波动导致丢包率飙升,策略直接“瞎了”。后来我加了一个序列号校验,如果发现跳号,就主动请求重传。这算是一个折中方案。
非阻塞I/O与epoll模型:让程序“忙而不乱”
做高频交易,最怕的就是程序“卡住”。比如你用阻塞式Socket收行情,如果网络延迟,整个线程就挂在那了。这在高频场景下是致命的。
非阻塞I/O,说白了就是:“我发个请求,不等你回复,我先干别的”。你调用recv,如果没有数据,它立刻返回一个错误码,而不是傻等。
但非阻塞I/O有个问题:你怎么知道什么时候有数据来了?总不能一直轮询吧?那太浪费CPU了。
这时候,epoll就登场了。它是Linux下最高效的I/O多路复用机制。你可以把它想象成一个“前台接待员”:你把所有Socket都告诉它,然后去忙别的。一旦某个Socket有数据了,它立刻通知你。
核心流程:
- 创建epoll实例:
epoll_create() - 注册事件:把需要监听的Socket加进去,告诉它“有数据读就通知我”
- 等待事件:
epoll_wait(),阻塞等待,直到有事件发生 - 处理事件:遍历返回的事件列表,挨个处理
一个简单的epoll示例:
int epfd = epoll_create(1);
struct epoll_event ev;
ev.events = EPOLLIN; // 监听可读事件
ev.data.fd = listen_fd;
epoll_ctl(epfd, EPOLL_CTL_ADD, listen_fd, &ev);
struct epoll_event events[1024];
while (1) {
int n = epoll_wait(epfd, events, 1024, -1);
for (int i = 0; i < n; i++) {
if (events[i].data.fd == listen_fd) {
// 新连接来了
} else {
// 有数据可读
}
}
}
你想想看,如果不用epoll,而是每个连接开一个线程,那1000个连接就是1000个线程。线程切换的开销,足以让你的交易延迟飙升。而epoll只用几个线程,就能管理成千上万个连接。
知识体系总览
下面这张图,是我对本章核心逻辑的总结。你可以把它当作一个“地图”,随时回来对照。
本章小结:网络编程是量化交易系统的“血管”。Socket是基础,TCP和UDP是工具,epoll是效率保障。记住:没有银弹,每种技术都有它的适用场景。多在实践中积累经验,慢慢你就能找到最适合自己系统的方案。