Socket.IOControl在dotnet core Linux上无法工作。

3

我目前正在开发一个使用Socket.IOControl实现keepalive的服务器,但是在dotnet core Linux上无法正常工作。当我尝试运行它时,会出现PlatformNotSupportedException

是否有跨平台的替代方案来实现dotnet core中的keepalive呢?

示例测试代码

private static void Main(string[] args)
{
    Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
    socket.Bind((EndPoint)new IPEndPoint(IPAddress.Loopback, 3178));
    socket.Listen(10);
    Console.WriteLine("Server: Begin Listening");
    socket.BeginAccept(new AsyncCallback(Program.AcceptCallback), (object)socket);
    Console.WriteLine("Client: Begin Connecting");
    TcpClient tcpClient = new TcpClient();
    tcpClient.Connect(new IPEndPoint(IPAddress.Loopback, 3178));
    Console.WriteLine("Client: Connected");
    Console.WriteLine("Client: Client keepAlive");
    Program.SetSocketKeepAliveValues(tcpClient.Client, 1000, 1);
    Thread.Sleep(50);
    Console.WriteLine("Done");
    Console.ReadLine();
}

private static void AcceptCallback(IAsyncResult ar)
{
    Socket asyncState = ar.AsyncState as Socket;
    try
    {
        Socket socket = asyncState.EndAccept(ar);
        Console.WriteLine("Server: Connection made");
        Console.WriteLine("Server: Set keepAlive");
        Program.SetSocketKeepAliveValues(socket, 1000, 1);
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
}

public static void SetSocketKeepAliveValues(Socket socket, int KeepAliveTime, int KeepAliveInterval)
{
    uint structure = 0;
    byte[] optionInValue = new byte[Marshal.SizeOf<uint>(structure) * 3];
    BitConverter.GetBytes(true ? 1U : 0U).CopyTo((Array)optionInValue, 0);
    BitConverter.GetBytes((uint)KeepAliveTime).CopyTo((Array)optionInValue, Marshal.SizeOf<uint>(structure));
    BitConverter.GetBytes((uint)KeepAliveInterval).CopyTo((Array)optionInValue, Marshal.SizeOf<uint>(structure) * 2);
    socket.IOControl(IOControlCode.KeepAliveValues, optionInValue, (byte[])null);
}

提前感谢


请发布一个SSCCE:http://sscce.org/。这里有关于KeepAlive的支持:https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.socketoptionname?view=netcore-2.0#System_Net_Sockets_SocketOptionName_KeepAlive。 - omajid
1
SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.KeepAlive,true); 启用保持活动状态,但间隔由操作系统管理,时间太长。 - Pepernoot
2个回答

5

根据这个 https://github.com/kburtram/corefx/commit/10791b0f6040e206887906a748fd119a16c6c2b9

您可以使用SetSocketOption设置KeepAlive。

this.socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
this.socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
this.socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveInterval, 5);
this.socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveRetryCount, 16);

1
仅在 .NetCore 3.0+ 中可用 - user11910061

3

[编辑] Dotnet Core现在支持KeepAlive

C 代码

#include <netinet/in.h>
#include <netinet/tcp.h>
#define check(expr) if (!(expr)) { return 0; }

int enable_keepalive(int sock, int enable_keepalive,int time, int interval,int maxpkt) {
    check(setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &enable_keepalive, sizeof(int)) != -1);

    check(setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &time, sizeof(int)) != -1);

    check(setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &interval, sizeof(int)) != -1);

    check(setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &maxpkt, sizeof(int)) != -1);
    return 1;
}

用法

[DllImport("libname.so")]
public static extern int enable_keepalive(int sock, int enable_keepalive,int time, int interval,int maxpkt);

private static void Main(string[] args)
{
    TcpClient tcpClient = new TcpClient();
    tcpClient.Connect(new IPEndPoint(IPAddress.Loopback, 3178));
    Console.WriteLine("Client: Connected");
    Console.WriteLine("Client: Client keepAlive");
    Console.WriteLine(enable_keepalive((int)tcpClient.Client.Handle,1,10,5, 2));
}

在Ubuntu 16.04上进行了测试。


你有这个 C# 代码的机会吗?毕竟,我们正在使用 dotNet :-) - Dominique

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接