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

如何在C# .NET Standard 2.1中设置TCP_KEEPIDLE等Socket参数?

在.NET Standard 2.1中设置TCP保活参数的方案

一、使用Socket.IOControl实现

TCP_KEEPIDLE、TCP_KEEPINTVL、TCP_KEEPCNT属于平台专属的套接字选项,.NET Standard的SetSocketOption未封装这些选项,但可以通过Socket.IOControl直接调用系统底层IO命令,需区分Windows和Linux平台:

1. Windows平台

Windows下使用SIO_KEEPALIVE_VALS控制码,通过结构体传递保活参数:

using System;
using System.Net.Sockets;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential)]
private struct TcpKeepAlive
{
    public uint OnOff;       // 1启用保活,0禁用
    public uint KeepAliveTime; // TCP_KEEPIDLE,单位毫秒
    public uint KeepAliveInterval; // TCP_KEEPINTVL,单位毫秒
}

public static void SetTcpKeepAliveWindows(Socket socket, int keepIdleMs, int keepIntervalMs)
{
    var keepAlive = new TcpKeepAlive
    {
        OnOff = 1,
        KeepAliveTime = (uint)keepIdleMs,
        KeepAliveInterval = (uint)keepIntervalMs
    };

    byte[] inBuffer = new byte[Marshal.SizeOf(keepAlive)];
    IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(keepAlive));
    Marshal.StructureToPtr(keepAlive, ptr, false);
    Marshal.Copy(ptr, inBuffer, 0, inBuffer.Length);
    Marshal.FreeHGlobal(ptr);

    // SIO_KEEPALIVE_VALS 控制码:0x98000004
    socket.IOControl(0x98000004, inBuffer, null);
}

注意:Windows没有套接字层面直接设置TCP_KEEPCNT(保活重试次数)的接口,该参数需通过系统注册表(如TcpMaxDataRetransmissions)配置。

2. Linux平台

Linux下通过SIOCSOCKOPT控制码调用原生setsockopt逻辑,分别设置三个参数:

using System;
using System.Net.Sockets;
using System.Runtime.InteropServices;

public static void SetTcpKeepAliveLinux(Socket socket, int keepIdleSeconds, int keepIntervalSeconds, int keepCount)
{
    // 先启用保活
    socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);

    // 设置TCP_KEEPIDLE(单位:秒)
    SetLinuxSocketOption(socket, SocketOptionLevel.Tcp, 4, keepIdleSeconds);
    // 设置TCP_KEEPINTVL(单位:秒)
    SetLinuxSocketOption(socket, SocketOptionLevel.Tcp, 5, keepIntervalSeconds);
    // 设置TCP_KEEPCNT(重试次数)
    SetLinuxSocketOption(socket, SocketOptionLevel.Tcp, 6, keepCount);
}

private static void SetLinuxSocketOption(Socket socket, SocketOptionLevel level, int optionName, int value)
{
    byte[] valueBytes = BitConverter.GetBytes(value);
    // SIOCSOCKOPT 控制码:0x8914
    socket.IOControl(0x8914, valueBytes, null);
}

说明:Linux下TCP_KEEPIDLE、TCP_KEEPINTVL的单位是秒,TCP_KEEPCNT为整数类型的重试次数。

二、备选方案:P/Invoke调用系统原生API

如果IOControl存在兼容性问题,可直接调用系统套接字API:

1. Windows平台调用WSAIoctl

[DllImport("ws2_32.dll", SetLastError = true)]
private static extern int WSAIoctl(
    IntPtr socketHandle,
    uint ioControlCode,
    IntPtr inBuffer,
    int inBufferSize,
    IntPtr outBuffer,
    int outBufferSize,
    out int bytesReturned,
    IntPtr overlapped,
    IntPtr completionRoutine);

public static void SetTcpKeepAliveWindowsPInvoke(Socket socket, int keepIdleMs, int keepIntervalMs)
{
    var keepAlive = new TcpKeepAlive
    {
        OnOff = 1,
        KeepAliveTime = (uint)keepIdleMs,
        KeepAliveInterval = (uint)keepIntervalMs
    };

    IntPtr inBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(keepAlive));
    Marshal.StructureToPtr(keepAlive, inBuffer, false);
    int bytesReturned;

    WSAIoctl(
        socket.Handle,
        0x98000004, // SIO_KEEPALIVE_VALS
        inBuffer,
        Marshal.SizeOf(keepAlive),
        IntPtr.Zero,
        0,
        out bytesReturned,
        IntPtr.Zero,
        IntPtr.Zero);

    Marshal.FreeHGlobal(inBuffer);
}

2. Linux平台调用setsockopt

[DllImport("libc", SetLastError = true)]
private static extern int setsockopt(
    IntPtr socketHandle,
    int level,
    int optionName,
    ref int optionValue,
    int optionLength);

public static void SetTcpKeepAliveLinuxPInvoke(Socket socket, int keepIdleSeconds, int keepIntervalSeconds, int keepCount)
{
    // 启用保活:SOL_SOCKET=1,SO_KEEPALIVE=9
    int enable = 1;
    setsockopt(socket.Handle, 1, 9, ref enable, sizeof(int));

    // 设置TCP_KEEPIDLE:IPPROTO_TCP=6,TCP_KEEPIDLE=4
    setsockopt(socket.Handle, 6, 4, ref keepIdleSeconds, sizeof(int));

    // 设置TCP_KEEPINTVL:TCP_KEEPINTVL=5
    setsockopt(socket.Handle, 6, 5, ref keepIntervalSeconds, sizeof(int));

    // 设置TCP_KEEPCNT:TCP_KEEPCNT=6
    setsockopt(socket.Handle, 6, 6, ref keepCount, sizeof(int));
}

三、关键注意事项

  • 平台适配:必须通过RuntimeInformation.IsOSPlatform判断当前系统,执行对应平台的代码逻辑。
  • 权限限制:Linux下部分环境可能要求进程拥有root权限才能修改这些套接字选项。
  • 系统配置:部分嵌入式Linux系统可能未开启TCP保活支持,需提前确认系统内核配置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 08:25:29