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

在C#中获取并复用C动态库返回的服务器句柄

C#与Linux动态库交互:正确存储和传递服务器句柄

你的核心问题是用object存储句柄类型不匹配,C语言返回的服务器句柄本质是指针(通常是void*),对应C#里的IntPtr类型,而非object。下面是修正后的实现方案:

1. 修正P/Invoke函数声明

把SendCommand的第一个参数从object改为IntPtr,保证类型和动态库的函数签名完全匹配:

[DllImport("server_connect.so", 
    EntryPoint = "fnConnect", 
    CallingConvention = CallingConvention.Cdecl, 
    CharSet = CharSet.Auto)]
static extern IntPtr fnConnect();

[DllImport("server_connect.so",
    EntryPoint = "fnSendCommand",
    CallingConvention = CallingConvention.Cdecl,
    CharSet = CharSet.Auto)]
static extern void fnSendCommand(IntPtr serverHandle, string command);

2. 安全存储与传递句柄

方案一:封装为类(推荐)

把连接逻辑、句柄存储、命令发送封装到类中,避免外部直接操作句柄,同时增加有效性校验:

public class ServerConnector
{
    private IntPtr _serverHandle = IntPtr.Zero;

    // 内部声明P/Invoke函数
    [DllImport("server_connect.so", 
        EntryPoint = "fnConnect", 
        CallingConvention = CallingConvention.Cdecl, 
        CharSet = CharSet.Auto)]
    private static extern IntPtr fnConnect();

    [DllImport("server_connect.so",
        EntryPoint = "fnSendCommand",
        CallingConvention = CallingConvention.Cdecl,
        CharSet = CharSet.Auto)]
    private static extern void fnSendCommand(IntPtr serverHandle, string command);

    /// <summary>
    /// 建立服务器连接
    /// </summary>
    /// <returns>是否连接成功</returns>
    public bool Connect()
    {
        _serverHandle = fnConnect();
        // 根据动态库规则判断句柄是否有效,一般用IntPtr.Zero表示无效
        return _serverHandle != IntPtr.Zero;
    }

    /// <summary>
    /// 发送命令到服务器
    /// </summary>
    /// <param name="command">命令内容</param>
    /// <exception cref="InvalidOperationException">未建立有效连接时抛出</exception>
    public void SendCommand(string command)
    {
        if (_serverHandle == IntPtr.Zero)
        {
            throw new InvalidOperationException("请先调用Connect建立服务器连接");
        }
        fnSendCommand(_serverHandle, command);
    }

    // 可选:添加断开连接方法(如果动态库提供fnDisconnect函数)
    // public void Disconnect()
    // {
    //     if (_serverHandle != IntPtr.Zero)
    //     {
    //         // 调用动态库的断开函数
    //         // fnDisconnect(_serverHandle);
    //         _serverHandle = IntPtr.Zero;
    //     }
    // }
}

使用方式:

var connector = new ServerConnector();
if (connector.Connect())
{
    connector.SendCommand("your_command_here");
}

方案二:直接使用IntPtr存储(简单场景)

如果不需要封装类,可以直接用IntPtr存储句柄,在后续调用时传入:

// 建立连接并获取句柄
IntPtr serverHandle = fnConnect();

// 校验句柄有效性后发送命令
if (serverHandle != IntPtr.Zero)
{
    fnSendCommand(serverHandle, "your_command_here");
}

关键说明

  • IntPtr是C#专门用于表示非托管指针/句柄的类型,和C语言的void*完全对应,避免object带来的类型装箱、拆箱和潜在的类型错误。
  • 无论哪种方案,都要在使用句柄前校验其有效性(比如判断是否等于IntPtr.Zero),防止调用无效句柄导致的崩溃。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 02:05:23