namespace FbMsg;

enum MsgType: uint
{
Unknown = 0,
LoginReqType = 101,
LoginRspType = 102,
EntrustType = 103,
EntrustRtnType = 104,
TradeRtnType = 105,
QryFundAccType = 106,
QryFundAccRspType = 107,
QryOrdersType = 108,
QryOrdersRspType = 109,
QryTradesType = 110,
QryTradesRspType = 111,
QryPositionsType = 112,
QryPositionsRspType = 113,
CancelOrderType = 114,
CancelOrderRtnType = 115,
ErrorInfoType = 116,
QryShareHolderType = 117,
QryShareHolderRspType = 118,
HeartBeatType = 119,
HeartBeatTypeRspType = 120,
AgentRegisterType = 121,
AgentRegisterRspType = 122
}
table Header
{
Msgtype: MsgType;
MsgLength: uint;
ChannelId: uint;
AccountId: uint;
ClientId: uint;
}

table LoginReq
{
ChannelId: string;
AccountId: string;
Password: string;
}

table LoginRsp
{
ChannelId: string;
AccountId: string;
TradingDay: string;
LoginTime: string;
MaxLocalId: uint32;
}

table Order
{
ChannelId: string;
ExchangeId: string;
InstrumentId: string;
AccountId: string;
OrderSysId: string;
Volume: long;
VolumeLeft: long;
VolumeTraded: long;
LimitPrice: double;
TradeAmount: double;
BuyOrSell: byte;
EnumBuySell: byte;
HedgeFlag: byte;
OrderPriceType: byte;
OpenOrClose: byte;
OrderStatus: byte;
InsertTime: string;
LocalInsertTime: string;
OrderId: string;
OrigOrderSysId: string;
OrigOrderId: string;
StatusMsg: string;
Trader: string;
}

table Trade
{
ChannelId: string;
ExchangeId: string;
InstrumentId: string;
AccountId: string;
OrderSysId: string;
OrderId: string;
TradeId: string;
Price: double;
Volume: long;
TradeTime: string;
BuyOrSell: byte;
HedgeFlag: byte;
OpenOrClose: byte;
UpdateTime: string;
Trader: string;
}

table FundAccount
{
ChannelId: string;
AccountId: string;
Available: double;
Balance: double;
UpdateTime: string;
}

table Position
{
ChannelId: string;
AccountId: string;
ExchangeId: string;
InstrumentId: string;
Name: string;
Volume: long;
EnableVolume: long;
YdVolume: long;
TdVolume: long;
AvgPrice: double;
BuyOrSell: byte;
HedgeFlag: byte;
UpdateTime: string;
}

table ErrorInfo
{
ChannelId: string;
AccountId: string;
ErrorId: uint;
ErrorMsg: string;
UpdateTime: string;
}

table QryReq
{
ChannelId: string;
AccountId: string;
}

table ShareHolder
{
ChannelId: string;
AccountId: string;
ExchangeId: string;
ShareHolderId: string;
ShareHolderName: string;
UpdateTime: string;
}

table HeartBeat
{
ChannelId: string;
AccountId: string;
LastTime: string;
ErrorId: uint;
ErrorMsg: string;
}

//伪代码

// 发送（消息发送序列）
// 1.target_id
// 2.msg(header+body)

// 接收（消息接收序列）
// 1.msg(hear+body)

class PackMsg
{
public:
PackMsg()
:m_msgLength(0)
{
m_buffer = new uchar_t[10240];
}


~PackMsg()
{
    if(m_buffer)
        delete m_buffer;
}

void PackMsg::pack(Header *header, uint8_t *msg, int msg_size)
{
    std::memcpy(m_buffer, header, sizeof(Header));
    std::memcpy(m_buffer+sizeof(Header), msg, msg_size);
    m_msgLength = msg_size + sizeof(Header);
}

void PackMsg::pack(Header *header)
{
    std::memcpy(m_buffer, header, sizeof(Header));
    m_msgLength = sizeof(Header);
}

uchar_t *PackMsg::getPackMsg()
{
    return m_buffer;
}

uint32_t PackMsg::getPackMsgLength()
{
    return m_msgLength;
}
private:
private:
uchar_t* m_buffer;
uint32_t m_msgLength;
}

// 发送
// 1.target_id
// 2.msg(header+body)
void insertOrder(Order& order)
{
FbMsg::OrderT orderT;
orderT.ChannelId = order.ChannelId;
orderT.ExchangeId = order.ExchangeId;
// ......
flatbuffers::FlatBufferBuilder builder(1024);
auto fbOrder = FbMsg::CreateOrder(builder,&orderT);
builder.Finish(fbOrder);


Header header;
header.MsgLength = sizeof(Header) + builder.GetSize();
header.MsgType = MsgType::EntrustType;
header.ChannelId = 101;
PackMsg msg;
msg.pack(&header, builder.GetBufferPointer(), builder.GetSize());

std::lock_guard<std::mutex> lock(m_mtx);
std::string target_id = "recv";
target_id = order.ChannelId + order.AccountId + target_id;
ZmqHelper::sendBuffMsg(m_pReqSocket, (uchar_t*)target_id.c_str(), target_id.length(), ZMQ_SNDMORE);
ZmqHelper::sendPackMsg(m_pReqSocket, &msg);
}

// 接收
// 1.msg(hear+body)
void Agent::listenMessages()
{
const int BUFFSIZE = 1024;
uchar_t buff[BUFFSIZE] = {0};


while(true)
{
    zmq_pollitem_t items[] = {{ m_pRspSocket, 0, ZMQ_POLLIN, 0 }};
    int rc = zmq_poll(items, 1, -1);
    if (rc == -1) {
        Logger::getInstance().log->error("Agent::listenMessages Poll error:{}",zmq_strerror(errno)); 
        break;
    }

    if(ZmqHelper::recvPackMsg(m_pRspSocket,buff)==-1)
    {
        continue;
    }

    Header header;
    memcpy(&header,buff,sizeof(Header));
    if(header.MsgType==MsgType::LoginReqType)
    {
        auto loginReq = flatbuffers::GetRoot<FbMsg::LoginReq>(buff+sizeof(Header));
        FbMsg::LoginReqT* loginReqT = loginReq->UnPack();
        handleLogin(header, loginReqT);
    }
    else if(header.MsgType==MsgType::EntrustType)
    {
        auto order = flatbuffers::GetRoot<FbMsg::Order>(buff+sizeof(Header));
        FbMsg::OrderT* orderT = order->UnPack();
        handleEntrust(header, orderT);
    }
    // ......
    memset(buff,0,sizeof(buff));
}
zmq_close (m_pRspSocket);
zmq_ctx_destroy (m_pRspContext);
}
结合上面C++ 代码，帮我写一个使用C# 发送心跳包和登录返回的方法，我已经将fbs生成了 cs类