#创造灵感#
:工作实践,最近实现了一个c++的消息总线类库,第三方使用C#需要调用,故做了一个demo程序
关于回调
c#使用delegate 定义回调签名。
传入结构体
c++定义的参数类型是结构体指针且结构体内部包含结构体动态数组指针,在定义C#结构体时外层结构体里面要用IntPtr代替内层结构体数组
传出结构体
此C++类库的设计是外部调用开辟内存空间,内部进行字符串和数字的填充。所以创建对应的C#结构体对象时字符串字段需要开辟足够的空间并以0填充
Don't BB,Show me Code!!!(c++头文件后续再发)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace MlinebusTest
{
public struct MBTopicExtern {
public string name;//主题名
public int rspModel;//消息应答类型,
public string version;//版本号,可以不填
}
public struct ConnectOptExtern {
public string host;//服务器地址
public int port;//服务器端口
public string groupName;//所在流水线组名,同一条流水线有相同的组名
public string userName;//用户名,
public string password;//密码
public string id; //用户唯一标识,全局唯一
public int role;//0-普通客户端,1-中控,需要知道其它节点是否上、下线
public IntPtr topics; //订阅主题数组
public int topicsSize;//主题长度
public int minRetryInterval;//最小间隔时间,
public int maxRetryInterval;//最大间隔时间,最小和最大间隔其中有一个为0将采用默认间隔时间1s和30s
}
public struct MsgExt {
public string groupName;//发送者组名
public string sender;//发送者id
public string version;//版本好
public string payload;//消息内容
public int payloadlen;//消息长度
}
//[StructLayout(LayoutKind.Sequential)]
public struct MsgRsp {
// [MarshalAs(UnmanagedType.ByValTStr,SizeConst =100)]
public string groupName;//发送者组名
// [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
public string sender;//发送者id
// [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
public string version;//版本好
// [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 2048)]
public string payload;//消息内容
public int payloadlen;//消息长度
};
public struct MBAddress {
string groupName;//用户所在组名
string userId;//用户id
};
public delegate void ReceiveMsgCBDelegate(string topic, int size, MsgExt ext);
public delegate void ConnectLostCBDelegate(string host , int port);
public delegate void TrackLogCBDelegate(string msg);
public delegate void UserOnlineChangedCBDelegate(string groupName,string userName , bool isOnline);
class Program
{
[DllImport("mlinebus.dll", EntryPoint = "mb_MBErrToStr")]
static extern IntPtr mb_MBErrToStr(int code);
[DllImport("mlinebus.dll",EntryPoint = "mb_connnect")]
static extern int mb_connnect(ConnectOptExtern option);
[DllImport("mlinebus.dll", EntryPoint = "mb_setCallback")]
static extern int mb_setCallback(ConnectLostCBDelegate ctlostcb, TrackLogCBDelegate logcb, ReceiveMsgCBDelegate receiveMsgcb, UserOnlineChangedCBDelegate userChangedcb);
[DllImport("mlinebus.dll", EntryPoint = "mb_request")]
static extern int mb_request(string topic, string payload, ref MsgRsp response, int timeout, string version, IntPtr address);
static void Main(string[] args)
{
Console.WriteLine("123");
IntPtr errmsg= mb_MBErrToStr(1);
string err = Marshal.PtrToStringAnsi(errmsg);
Console.WriteLine(err);
ConnectLostCBDelegate ctlostcb= ConnectLostCBHandler;
TrackLogCBDelegate logcb= TrackLogCBHandler;
ReceiveMsgCBDelegate receiveMsgcb = ReceiveMsgCBHandler;
UserOnlineChangedCBDelegate userChangedcb= UserOnlineChangedCBHandler;
int code=mb_setCallback(ctlostcb, logcb, receiveMsgcb, userChangedcb);
if (code == 0)
{
Console.WriteLine("mb_setCallback success");
}
else {
Console.WriteLine("mb_setCallback failed");
Console.ReadKey();
return;
}
ConnectOptExtern opt=new ConnectOptExtern();
opt.host = "127.0.0.1";
opt.port = 1883;
opt.groupName = "testline";
opt.userName = "6001";
opt.password = "maccura";
opt.id = "6001_1";
// opt.topics = new MBTopicExtern[2];
int topicCount = 3;
opt.topicsSize = topicCount;
int topicSize = Marshal.SizeOf<MBTopicExtern>();
Console.WriteLine("size of MBTopicExtern="+ topicSize);
IntPtr pBuff = Marshal.AllocHGlobal(topicSize * topicCount);
long ptrHead = pBuff.ToInt64();
MBTopicExtern[] topic = new MBTopicExtern[topicCount];
topic[0].name = "firstTopic";
topic[0].rspModel = 0;
topic[0].version = "";
IntPtr firstPtr = new IntPtr(ptrHead);
Marshal.StructureToPtr(topic[0], firstPtr, false);
topic[1].name = "secondTopic";
topic[1].rspModel = 0;
topic[1].version = "";
IntPtr secondPtr = new IntPtr(ptrHead+ topicSize);
Marshal.StructureToPtr(topic[1], secondPtr, false);
topic[2].name = "orderinfo";
topic[2].rspModel = 1;//request
topic[2].version = "";
IntPtr thirdPtr = new IntPtr(ptrHead + topicSize*2);
Marshal.StructureToPtr(topic[2], thirdPtr, false);
opt.topics = pBuff;
int ret = mb_connnect(opt);
//release memory
Marshal.FreeHGlobal(pBuff);
//demo how to request
MsgRsp rsp = new MsgRsp();
rsp.groupName = new String(new char[100]);
rsp.sender = new String(new char[100]);
rsp.version = new String(new char[100]);
char[] a = new char[10000];
rsp.payload = new String(new char[100]);
rsp.payloadlen = 10000;
int rspSize = Marshal.SizeOf<MsgRsp>();
// IntPtr rspPtr = Marshal.AllocHGlobal(rspSize);
// Marshal.StructureToPtr(rsp, rspPtr, false);
code = mb_request("orderinfo", "{name:123}", ref rsp, 5, "", IntPtr.Zero);
if (code != 0)
{
Console.WriteLine("request failed,code= " + code);
}
else
{
// var result= Marshal.PtrToStructure<MsgRsp>(rspPtr);
Console.WriteLine("request success:");
Console.WriteLine("response groupName= " + rsp.groupName);
Console.WriteLine("response sender= " + rsp.sender);
Console.WriteLine("response version= " + rsp.version);
Console.WriteLine("response payloadlen= " + rsp.payloadlen);
Console.WriteLine("response payload= " + rsp.payload.ToString());
}
while (Console.ReadKey().KeyChar != 'a') { };
}
public static void ReceiveMsgCBHandler(string topic, int size, MsgExt ext) {
Console.WriteLine("ReceiveMsgCBHandler called:");
Console.WriteLine(" topic= " + topic);
Console.WriteLine(" size= " + size);
Console.WriteLine(" payloadlen= " + ext.payloadlen);
Console.WriteLine(" payload= " + ext.payload);
}
public static void ConnectLostCBHandler(string host, int port) {
Console.WriteLine("ConnectLostCBHandler called: host="+host+" ,port="+port);
}
public static void TrackLogCBHandler(string msg) {
Console.WriteLine("TrackLogCBHandler called");
Console.WriteLine("TrackLogCBHandler called: "+ msg);
}
public static void UserOnlineChangedCBHandler(string groupName, string userName, bool isOnline) {
Console.WriteLine("UserOnlineChangedCBHandler called");
}
}
}