Home All Groups Group Topic Archive Search About

Using TCP/IP KeepAlive in C#

Author
3 Aug 2006 3:04 PM
Roy Chastain
I have been trying to make NetSocket.SetSocketOption work for TCP/IP KeepAlive

I have tried the following code

        public virtual void SetKeepAlive (ulong keepalive_time, ulong keepalive_interval)
        {
            int                                                                                bytes_per_long = 32 / 8;
            byte []                                                                        keep_alive = new byte[3*bytes_per_long];
            ulong    []                                                                    input_params = new ulong[3];
            int                                                                                i1;
            int                                                                             bits_per_byte = 8;

            if (keepalive_time == 0 || keepalive_interval == 0)
                input_params[0] = 0;
            else
                input_params[0] = 1;
            input_params[1] = keepalive_time;
            input_params[2] = keepalive_interval;
            for (i1=0; i1<input_params.Length; i1++)
            {
                keep_alive[i1*bytes_per_long+3] = (byte)(input_params[i1] >> ((bytes_per_long - 1) * bits_per_byte) & 0xff);
                keep_alive[i1*bytes_per_long+2] = (byte)(input_params[i1] >> ((bytes_per_long - 2) * bits_per_byte) & 0xff);
                keep_alive[i1*bytes_per_long+1] = (byte)(input_params[i1] >> ((bytes_per_long - 3) * bits_per_byte) & 0xff);
                keep_alive[i1*bytes_per_long+0] = (byte)(input_params[i1] >> ((bytes_per_long - 4) * bits_per_byte) & 0xff);
            }
            LogTrace.Trace(this,"Keep Alive Bits: {0}",ByteArrayFormater.HexDump(keep_alive));
            NetSocket.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.KeepAlive,keep_alive);
        }        /* method AsyncSocket SetKeepAlive */


The result is not error, no exception and no keepalive in the expected time frame.
I am passing both times in mill-seconds.  The Trace that I have shows 12 bytes in the form of
01 00 00 00 10 27 00 00 98 3a 00 00  when called as SetKeepAlive(10000,15000);

I am not really sure if I need to put the bytes in this order or not.  If working directly with the Winsock API, the keepalive
option uses a structure of 3 ULONGS with a 1 in the first one, the time in the 2nd one and the retry time (interval in this code)
in the third one.

Any help on this would be appreciated.
-------------------------------------------
Roy Chastain
KMSYS Worldwide, Inc.
http://www.kmsys.com

Author
3 Aug 2006 4:16 PM
Goran Sliskovic
Roy Chastain wrote:
Show quote
> I have been trying to make NetSocket.SetSocketOption work for TCP/IP KeepAlive
>
> I have tried the following code
>
>         public virtual void SetKeepAlive (ulong keepalive_time, ulong keepalive_interval)
>         {
>             int                                                                                bytes_per_long = 32 / 8;
>             byte []                                                                        keep_alive = new byte[3*bytes_per_long];
....

>             LogTrace.Trace(this,"Keep Alive Bits: {0}",ByteArrayFormater.HexDump(keep_alive));
>             NetSocket.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.keep alive,keep_alive);
>         }        /* method AsyncSocket SetKeepAlive */
>
>
> The result is not error, no exception and no keepalive in the expected time frame.
> I am passing both times in mill-seconds.  The Trace that I have shows 12 bytes in the form of
> 01 00 00 00 10 27 00 00 98 3a 00 00  when called as SetKeepAlive(10000,15000);
....

I'm not sure that .NET implementation expects timeouts. I think it
expects bool (enable/disable). Maybe you cold PInvoke WSAIoctl...

Regards,
Goran
Author
3 Aug 2006 4:22 PM
appzguy
I have done this in the past

socket.SetSocketOption(SocketOptionLevel.Tcp,SocketOptionName.KeepAlive,1);

and then I tweaked the registry entries to set keep-alive intervals
The reg keys are located at
[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Tcpip\Parameters]

KeepAliveTime = milliseconds
Specifies the connection idle time in milliseconds before TCP will
begin sending keepalives, if keepalives are enabled on a connection.
The default is 2 hours (7,200,000).

KeepAliveInterval = 32-bit number
Specifies the time in milliseconds between retransmissions of
keepalives, once the KeepAliveTime has expired. Once KeepAliveTime has
expired, keepalives are sent every KeepAliveInterval milliseconds until
a response is received, up to a maximum of MaxDataRetries before the
connection is terminated. The default is 1 second (1000).


Roy Chastain wrote:
Show quote
> I have been trying to make NetSocket.SetSocketOption work for TCP/IP KeepAlive
>
> I have tried the following code
>
>         public virtual void SetKeepAlive (ulong keepalive_time, ulong keepalive_interval)
>         {
>             int                                                                                bytes_per_long = 32 / 8;
>             byte []                                                                        keep_alive = new byte[3*bytes_per_long];
>             ulong    []                                                                    input_params = new ulong[3];
>             int                                                                                i1;
>             int                                                                             bits_per_byte = 8;
>
>             if (keepalive_time == 0 || keepalive_interval == 0)
>                 input_params[0] = 0;
>             else
>                 input_params[0] = 1;
>             input_params[1] = keepalive_time;
>             input_params[2] = keepalive_interval;
>             for (i1=0; i1<input_params.Length; i1++)
>             {
>                 keep_alive[i1*bytes_per_long+3] = (byte)(input_params[i1] >> ((bytes_per_long - 1) * bits_per_byte) & 0xff);
>                 keep_alive[i1*bytes_per_long+2] = (byte)(input_params[i1] >> ((bytes_per_long - 2) * bits_per_byte) & 0xff);
>                 keep_alive[i1*bytes_per_long+1] = (byte)(input_params[i1] >> ((bytes_per_long - 3) * bits_per_byte) & 0xff);
>                 keep_alive[i1*bytes_per_long+0] = (byte)(input_params[i1] >> ((bytes_per_long - 4) * bits_per_byte) & 0xff);
>             }
>             LogTrace.Trace(this,"Keep Alive Bits: {0}",ByteArrayFormater.HexDump(keep_alive));
>             NetSocket.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.KeepAlive,keep_alive);
>         }        /* method AsyncSocket SetKeepAlive */
>
>
> The result is not error, no exception and no keepalive in the expected time frame.
> I am passing both times in mill-seconds.  The Trace that I have shows 12 bytes in the form of
> 01 00 00 00 10 27 00 00 98 3a 00 00  when called as SetKeepAlive(10000,15000);
>
> I am not really sure if I need to put the bytes in this order or not.  If working directly with the Winsock API, the keepalive
> option uses a structure of 3 ULONGS with a 1 in the first one, the time in the 2nd one and the retry time (interval in this code)
> in the third one.
>
> Any help on this would be appreciated.
> -------------------------------------------
> Roy Chastain
> KMSYS Worldwide, Inc.
> http://www.kmsys.com
Author
3 Aug 2006 4:55 PM
Roy Chastain
Thanks for you comments.  Your solution explains the note in the doc that says that KeepAlives can be enabled with the form of the
function that uses the int as the 3rd parameter.

I might go that way for a bit, but in the long run I want more control than the registry offers.  (I want different sockets to
have different values.)


On 3 Aug 2006 09:22:50 -0700, appz***@gmail.com wrote:

Show quote
>I have done this in the past
>
>socket.SetSocketOption(SocketOptionLevel.Tcp,SocketOptionName.KeepAlive,1);
>
>and then I tweaked the registry entries to set keep-alive intervals
>The reg keys are located at
>[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Tcpip\Parameters]
>
>KeepAliveTime = milliseconds
>Specifies the connection idle time in milliseconds before TCP will
>begin sending keepalives, if keepalives are enabled on a connection.
>The default is 2 hours (7,200,000).
>
>KeepAliveInterval = 32-bit number
>Specifies the time in milliseconds between retransmissions of
>keepalives, once the KeepAliveTime has expired. Once KeepAliveTime has
>expired, keepalives are sent every KeepAliveInterval milliseconds until
>a response is received, up to a maximum of MaxDataRetries before the
>connection is terminated. The default is 1 second (1000).
>
>
>Roy Chastain wrote:
>> I have been trying to make NetSocket.SetSocketOption work for TCP/IP KeepAlive
>>
>> I have tried the following code
>>
>>         public virtual void SetKeepAlive (ulong keepalive_time, ulong keepalive_interval)
>>         {
>>             int                                                                                bytes_per_long = 32 / 8;
>>             byte []                                                                        keep_alive = new byte[3*bytes_per_long];
>>             ulong    []                                                                    input_params = new ulong[3];
>>             int                                                                                i1;
>>             int                                                                             bits_per_byte = 8;
>>
>>             if (keepalive_time == 0 || keepalive_interval == 0)
>>                 input_params[0] = 0;
>>             else
>>                 input_params[0] = 1;
>>             input_params[1] = keepalive_time;
>>             input_params[2] = keepalive_interval;
>>             for (i1=0; i1<input_params.Length; i1++)
>>             {
>>                 keep_alive[i1*bytes_per_long+3] = (byte)(input_params[i1] >> ((bytes_per_long - 1) * bits_per_byte) & 0xff);
>>                 keep_alive[i1*bytes_per_long+2] = (byte)(input_params[i1] >> ((bytes_per_long - 2) * bits_per_byte) & 0xff);
>>                 keep_alive[i1*bytes_per_long+1] = (byte)(input_params[i1] >> ((bytes_per_long - 3) * bits_per_byte) & 0xff);
>>                 keep_alive[i1*bytes_per_long+0] = (byte)(input_params[i1] >> ((bytes_per_long - 4) * bits_per_byte) & 0xff);
>>             }
>>             LogTrace.Trace(this,"Keep Alive Bits: {0}",ByteArrayFormater.HexDump(keep_alive));
>>             NetSocket.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.KeepAlive,keep_alive);
>>         }        /* method AsyncSocket SetKeepAlive */
>>
>>
>> The result is not error, no exception and no keepalive in the expected time frame.
>> I am passing both times in mill-seconds.  The Trace that I have shows 12 bytes in the form of
>> 01 00 00 00 10 27 00 00 98 3a 00 00  when called as SetKeepAlive(10000,15000);
>>
>> I am not really sure if I need to put the bytes in this order or not.  If working directly with the Winsock API, the keepalive
>> option uses a structure of 3 ULONGS with a 1 in the first one, the time in the 2nd one and the retry time (interval in this code)
>> in the third one.
>>
>> Any help on this would be appreciated.
>> -------------------------------------------
>> Roy Chastain
>> KMSYS Worldwide, Inc.
>> http://www.kmsys.com
-------------------------------------------
Roy Chastain
KMSYS Worldwide, Inc.
http://www.kmsys.com
Author
10 Aug 2006 9:55 AM
Gary Chang[MSFT]
Hi Roy,

In Windows 2000 and later Windows operating systems, we can control the
per-connection setting of keep-alive option, keepalive time, and keepalive
interval. Basically, this could be done by the PSDK API WSAIoctl(...) with
the SIO_KEEPALIVE_VALS as its IOControlCode:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/win
sock/wsaioctl_2.asp


The .NET framework also provides a method to access that low level
functionality: Socket.IOControl. I found a newsgroup thread which discuss
the usage on using the SIO_KEEPALIVE_VALS:

Socket.IOControl and SIO_KEEPALIVE_VALS
http://groups.google.com/group/microsoft.public.dotnet.languages.csharp/brow
se_thread/thread/a71b3a2912595769/48c72a728cc51a57?lnk=st&q=&rnum=1&hl=en#48
c72a728cc51a57

Socket.IOControl Method (IOControlCode, Byte[], Byte[]) 
http://msdn2.microsoft.com/en-us/library/8a3744sh.aspx


I hope the above information helps, if you have any issues or concerns
please let me know. I will be happy to be of further assistance.

Thanks!

Best regards,

Gary Chang
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
Author
10 Aug 2006 10:47 AM
Roy Chastain
Okay, the message  thread you pointed me is a discussion of Socket.IOControl that gets fairly messy in the 1.1 environment.  I am
in the 1.1 environment..

My attempt uses Socket.SetSocketOption and eventually these 2 methods should end up running through the same code in WinSock.  I
know how to set a KeepAlive in C++ using WinSock.  I have been doing that for years.

The question that still remains using IOControl is, "What is the proper packing of the ULONGS into the byte array?" 

Given the SIO_KEEPALIVE_VALS structure of
struct tcp_keepalive {
    u_long  onoff;
    u_long  keepalivetime;
    u_long  keepaliveinterval;
};

onoff will be 1
keepalivetime will be 10000
keepaliveinterval will be 15000

Should the byte array be packed like this
01 00 00 00 10 27 00 00 98 3a 00 00
or should they be packed like this
00 00 00 01 00 00 27 10 00 00 3a 98
or possibly some other pattern I have not figured out?
AND is this pattern machine dependent.  (Intel vs. rest of the world?)

Also as an aside, do we expect SetSocketOption to work once the bytes are in the correct order or do I have to change to
IOControl?  If we do not expect tSetSocketOption to work, then KeepAlive should be removed from the SocketOptionName enumeration.


On Thu, 10 Aug 2006 09:55:17 GMT, v-gar***@online.microsoft.com ("Gary Chang[MSFT]") wrote:

Show quote
>Hi Roy,
>
>In Windows 2000 and later Windows operating systems, we can control the
>per-connection setting of keep-alive option, keepalive time, and keepalive
>interval. Basically, this could be done by the PSDK API WSAIoctl(...) with
>the SIO_KEEPALIVE_VALS as its IOControlCode:
>
>http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/win
>sock/wsaioctl_2.asp
>
>
>The .NET framework also provides a method to access that low level
>functionality: Socket.IOControl. I found a newsgroup thread which discuss
>the usage on using the SIO_KEEPALIVE_VALS:
>
>Socket.IOControl and SIO_KEEPALIVE_VALS
>http://groups.google.com/group/microsoft.public.dotnet.languages.csharp/brow
>se_thread/thread/a71b3a2912595769/48c72a728cc51a57?lnk=st&q=&rnum=1&hl=en#48
>c72a728cc51a57
>
>Socket.IOControl Method (IOControlCode, Byte[], Byte[]) 
>http://msdn2.microsoft.com/en-us/library/8a3744sh.aspx
>
>
>I hope the above information helps, if you have any issues or concerns
>please let me know. I will be happy to be of further assistance.
>
>Thanks!
>
>Best regards,
>
>Gary Chang
>Microsoft Online Community Support
>==================================================
>Get notification to my posts through email? Please refer to
>http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
>ications.
>==================================================
>This posting is provided "AS IS" with no warranties, and confers no rights.
-------------------------------------------
Roy Chastain
KMSYS Worldwide, Inc.
http://www.kmsys.com
Author
11 Aug 2006 7:15 AM
Gary Chang[MSFT]
Hi Roy,

>Okay, the message  thread you pointed me is a discussion
>of Socket.IOControl that gets fairly messy in the 1.1
>environment.  I am in the 1.1 environment..

Just as that thread discussed, you can define the enum code manually:

SIO_KEEPALIVE_VALS is:
-1744830460 (or 0x98000004)


>Should the byte array be packed like this
>01 00 00 00 10 27 00 00 98 3a 00 00

The above is exactly the raw byte array layout of the struct tcp_keepalive
in little endian machine, you can take this one in most Windows platforms.
But it would be better to write some little code to test the machine's
endian type, then transfer the proper byte array due to the machine's
endian type.

>Also as an aside, do we expect SetSocketOption to work once
>the bytes are in the correct order or do I have to change to
>IOControl?

The .NET framework's SetSocketOption method hasn't provided much control to
low level socket settings. Its socket option for the keep alive feature
could only be zero or non-zero value, it is used to enable or disable the
KeepAlive feature. So pass a byte array  would not work. I suggest you take
the IOControl approach.

Thanks for your understanding.

Best regards,

Gary Chang
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.

AddThis Social Bookmark Button