You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Python simplefix+Socket维持FIX会话:解决返回None错误

如何维持FIX会话连接

我用Python的simplefix与socket模块开发FIX客户端,发送Logon登录报文和行情数据请求后,可正常接收所需行情约5分钟,之后持续返回'none'错误。如何维持FIX会话连接?

发送代码

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))

s.sendall(logon())
print(parse(s.recv(4096), 50))

s.sendall(market_data())
while True:
    print(s.recv(4096))

服务端响应

8=FIX.4.4|9=106|35=A|34=1|49=CSERVER|50=QUOTE|52=20230128-21:45:28.927|56=demo.roboforex.6183532|57=any|98=0|108=30|141=Y|10=228
b'8=FIX.4.4\x019=135\x0135=W\x0134=2\x0149=CSERVER\x0150=QUOTE\x0152=20230128-21:45:28.988\x0156=demo.roboforex.6183532\x0157=any\x0155=1\x01268=2\x01269=0\x01270=1.08677\x01269=1\x01270=1.08678\x0110=075\x01'
b'8=FIX.4.4\x019=88\x0135=0\x0134=3\x0149=CSERVER\x0150=QUOTE\x0152=20230128-21:45:59.917\x0156=demo.roboforex.6183532\x0157=any\x0110=107\x01'
b'8=FIX.4.4\x019=97\x0135=1\x0134=4\x0149=CSERVER\x0150=QUOTE\x0152=20230128-21:46:14.917\x0156=demo.roboforex.6183532\x0157=any\x01112=TEST\x0110=119\x01'
none
none
none
none
none
none
none
none
none
none
none
none
none
none
none
none
none
none
none
none
none
none

解决方案

1. 严格处理心跳机制

从服务端返回的Logon报文(35=A)可见108=30,这表示会话心跳间隔为30秒。你需要:

  • 每隔30秒主动发送心跳报文(35=0)
  • 监听服务端发来的心跳请求,及时回复心跳
  • 超过心跳间隔1.5倍时间未收到对方报文时,触发连接检查逻辑

2. 维护消息序号连续性

每个FIX报文的34字段是递增的消息序号,必须:

  • 本地维护发送序号,每次发报文后序号+1
  • 接收服务端报文时验证序号连续性,出现断层则排查连接状态

3. 正确处理Socket连接断开

当recv()返回空字节串或None时,说明服务端已关闭连接,此时需要:

  • 关闭当前socket
  • 重新发起连接并发送Logon报文重建会话
  • 恢复行情数据请求流程

4. 优化报文解析逻辑

当前直接用recv(4096)可能导致报文粘包或截断,建议用simplefix的解析器逐段处理:

import simplefix
import socket
import time

def main():
    HOST = "你的服务器地址"
    PORT = 你的端口号

    fix_parser = simplefix.FixParser()
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((HOST, PORT))

    # 发送Logon报文(确保logon函数设置了108=30和141=Y)
    logon_msg = logon()
    s.sendall(logon_msg)

    # 解析Logon响应
    data = s.recv(4096)
    fix_parser.append_buffer(data)
    while True:
        msg = fix_parser.get_message()
        if msg:
            print(parse(msg, 50))
            break

    # 发送行情请求
    s.sendall(market_data())
    send_seq = 2  # 已发送Logon(1)和行情请求(2)
    last_heartbeat_time = time.time()
    heartbeat_interval = 30  # 与Logon报文中的108保持一致

    while True:
        # 处理接收数据
        data = s.recv(4096)
        if not data:
            print("连接断开,尝试重连...")
            s.close()
            # 重连流程
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.connect((HOST, PORT))
            s.sendall(logon())
            # 等待重连后的Logon响应
            data = s.recv(4096)
            fix_parser.append_buffer(data)
            while True:
                msg = fix_parser.get_message()
                if msg:
                    print(parse(msg, 50))
                    send_seq = 1
                    last_heartbeat_time = time.time()
                    break
            continue

        fix_parser.append_buffer(data)
        while True:
            msg = fix_parser.get_message()
            if not msg:
                break
            print(msg)
            # 响应服务端的心跳请求(35=0)
            if msg.get(35) == b'0':
                heartbeat_msg = simplefix.FixMessage()
                heartbeat_msg.append_pair(8, b'FIX.4.4')
                heartbeat_msg.append_pair(35, b'0')
                heartbeat_msg.append_pair(34, str(send_seq).encode())
                heartbeat_msg.append_pair(49, b'demo.roboforex.6183532')
                heartbeat_msg.append_pair(56, b'CSERVER')
                heartbeat_msg.append_pair(52, time.strftime("%Y%m%d-%H:%M:%S.%f")[:-3].encode())
                s.sendall(heartbeat_msg.encode())
                send_seq += 1
                last_heartbeat_time = time.time()
            # 响应服务端的测试请求(35=1)
            if msg.get(35) == b'1':
                heartbeat_msg = simplefix.FixMessage()
                heartbeat_msg.append_pair(8, b'FIX.4.4')
                heartbeat_msg.append_pair(35, b'0')
                heartbeat_msg.append_pair(34, str(send_seq).encode())
                heartbeat_msg.append_pair(49, b'demo.roboforex.6183532')
                heartbeat_msg.append_pair(56, b'CSERVER')
                heartbeat_msg.append_pair(52, time.strftime("%Y%m%d-%H:%M:%S.%f")[:-3].encode())
                # 携带测试请求的112字段
                test_req_id = msg.get(112)
                if test_req_id:
                    heartbeat_msg.append_pair(112, test_req_id)
                s.sendall(heartbeat_msg.encode())
                send_seq += 1
                last_heartbeat_time = time.time()

        # 检查是否需要主动发送心跳
        if time.time() - last_heartbeat_time > heartbeat_interval:
            heartbeat_msg = simplefix.FixMessage()
            heartbeat_msg.append_pair(8, b'FIX.4.4')
            heartbeat_msg.append_pair(35, b'0')
            heartbeat_msg.append_pair(34, str(send_seq).encode())
            heartbeat_msg.append_pair(49, b'demo.roboforex.6183532')
            heartbeat_msg.append_pair(56, b'CSERVER')
            heartbeat_msg.append_pair(52, time.strftime("%Y%m%d-%H:%M:%S.%f")[:-3].encode())
            s.sendall(heartbeat_msg.encode())
            send_seq += 1
            last_heartbeat_time = time.time()

        time.sleep(1)  # 避免循环过度占用资源

if __name__ == "__main__":
    main()

5. 响应测试请求

服务端返回的报文中出现了35=1(Test Request),必须携带对应的112字段回复心跳,否则服务端会判定连接异常并断开。

内容的提问来源于stack exchange,提问作者werwer werwer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 21:01:37