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

寻求C++Builder下Indy的TCP示例及ISO8583中间人网关入门模板

C++Builder + Indy 10 TCP中间人网关模板(适配ISO8583分析场景)

核心实现逻辑

  • 用TIdTCPServer监听客户端连接,每收到一个客户端连接,动态创建TIdTCPClient实例连接真实服务器
  • 实现客户端与服务器的数据流双向转发,同时捕获原始二进制数据用于后续ISO8583解析
  • 处理连接断开的异常与资源释放,确保网关稳定运行

完整代码模板

步骤1:组件准备

在C++Builder窗体中添加以下组件:

  • TIdTCPServer(命名为IdTCPServer1)
  • TMemo(命名为MemoLog,用于记录日志和数据,可选)

步骤2:代码实现

#include <vcl.h>
#pragma hdrstop

#include "MainForm.h"
#include <IdTCPClient.hpp>
#include <IdTCPConnection.hpp>
#include <IdTCPServer.hpp>
#include <IdGlobal.hpp>
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;

// 关联客户端与服务器连接的结构体
struct TClientServerPair {
    TIdContext* ClientContext;
    TIdTCPClient* ServerClient;
    bool IsActive;
};

// 存储所有活跃连接对
TList* ClientServerPairs = new TList();
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
    // 配置监听服务器
    IdTCPServer1->DefaultPort = 10000; // 替换为你的监听端口
    IdTCPServer1->OnConnect = &IdTCPServer1Connect;
    IdTCPServer1->OnDisconnect = &IdTCPServer1Disconnect;
    IdTCPServer1->OnExecute = &IdTCPServer1Execute;
    IdTCPServer1->Active = true;
    MemoLog->Lines->Add("中间人网关已启动,监听端口:10000");
}
//---------------------------------------------------------------------------
void __fastcall TForm1::IdTCPServer1Connect(TIdContext *AContext)
{
    MemoLog->Lines->Add("客户端连接:" + AContext->Binding->PeerIP + ":" + IntToStr(AContext->Binding->PeerPort));

    // 创建并连接真实服务器
    TIdTCPClient* ServerClient = new TIdTCPClient(this);
    ServerClient->Host = "127.0.0.1"; // 替换为真实服务器IP
    ServerClient->Port = 20000; // 替换为真实服务器端口
    ServerClient->ConnectTimeout = 5000;

    try {
        ServerClient->Connect();
        MemoLog->Lines->Add("已连接到真实服务器");

        // 保存连接对并关联到客户端上下文
        TClientServerPair* Pair = new TClientServerPair();
        Pair->ClientContext = AContext;
        Pair->ServerClient = ServerClient;
        Pair->IsActive = true;
        ClientServerPairs->Add(Pair);
        AContext->Data = Pair;
    }
    catch (Exception& E) {
        MemoLog->Lines->Add("连接真实服务器失败:" + E.Message);
        delete ServerClient;
        AContext->Connection->Disconnect();
    }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::IdTCPServer1Disconnect(TIdContext *AContext)
{
    MemoLog->Lines->Add("客户端断开:" + AContext->Binding->PeerIP + ":" + IntToStr(AContext->Binding->PeerPort));

    // 清理对应服务器连接
    TClientServerPair* Pair = static_cast<TClientServerPair*>(AContext->Data);
    if (Pair && Pair->IsActive) {
        Pair->IsActive = false;
        if (Pair->ServerClient->Connected()) {
            Pair->ServerClient->Disconnect();
        }
        delete Pair->ServerClient;
        ClientServerPairs->Remove(Pair);
        delete Pair;
    }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::IdTCPServer1Execute(TIdContext *AContext)
{
    TClientServerPair* Pair = static_cast<TClientServerPair*>(AContext->Data);
    if (!Pair || !Pair->IsActive || !Pair->ServerClient->Connected()) {
        return;
    }

    TIdTCPConnection* ClientConn = AContext->Connection;
    TIdTCPConnection* ServerConn = Pair->ServerClient->Connection;

    // 读取客户端二进制数据并转发
    if (ClientConn->IOHandler->InputBuffer->Size > 0) {
        TIdBytes ClientData;
        // 按可用数据全读,后续可根据ISO8583长度字段调整读取逻辑
        ClientConn->IOHandler->ReadBytes(ClientData, ClientConn->IOHandler->InputBuffer->Size);
        
        // 记录十六进制格式数据,方便解析
        AnsiString HexData = BytesToHex(ClientData);
        MemoLog->Lines->Add("收到客户端数据(Hex):" + HexData);

        ServerConn->IOHandler->Write(ClientData);
    }

    // 读取服务器响应并转发给客户端
    if (ServerConn->IOHandler->InputBuffer->Size > 0) {
        TIdBytes ServerData;
        ServerConn->IOHandler->ReadBytes(ServerData, ServerConn->IOHandler->InputBuffer->Size);
        
        AnsiString HexData = BytesToHex(ServerData);
        MemoLog->Lines->Add("收到服务器响应(Hex):" + HexData);

        ClientConn->IOHandler->Write(ServerData);
    }

    // 检测连接状态,异常则断开
    if (!ClientConn->Connected() || !ServerConn->Connected()) {
        AContext->Connection->Disconnect();
    }
}
//---------------------------------------------------------------------------
__fastcall TForm1::~TForm1()
{
    // 程序退出时清理所有连接
    for (int i = 0; i < ClientServerPairs->Count; i++) {
        TClientServerPair* Pair = static_cast<TClientServerPair*>(ClientServerPairs->Items[i]);
        if (Pair->IsActive) {
            if (Pair->ServerClient->Connected()) {
                Pair->ServerClient->Disconnect();
            }
            delete Pair->ServerClient;
            Pair->IsActive = false;
        }
        delete Pair;
    }
    delete ClientServerPairs;
}

关键问题解决

1. 连接断开无提示

  • 利用TIdTCPServer的OnDisconnect事件捕获客户端断开,同时在OnExecute循环中定期检查客户端和服务器的连接状态
  • 客户端断开时主动断开对应服务器连接并释放资源,避免内存泄漏

2. 获取实际二进制数据

  • 必须使用ReadBytes()读取原始二进制流,禁止使用ReadLn()等文本读取方法
  • 通过BytesToHex()将二进制转为十六进制字符串,便于查看和后续ISO8583解析
  • 后续可根据ISO8583协议的长度字段(如前2字节表示报文长度),调整ReadBytes()的参数实现精准读取

后续扩展建议

  • 将数据捕获逻辑独立为模块,把ClientData和ServerData传递给ISO8583解析组件
  • 添加配置界面,支持动态修改监听端口、服务器IP/端口
  • 增加日志持久化功能,将报文数据保存到文件或数据库
  • 实现报文过滤、修改功能,满足中间人分析的定制需求

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 13:05:36