les*_*rid 59 c# sockets connection
如果其他主机在断开连接时没有向您发送数据包(例如因为它不正常地断开连接),如何检查网络套接字(System.Net.Sockets.Socket)是否仍然连接?
zen*_*dar 91
由于保罗特纳 回答Socket.Connected不能在这种情况下使用.您需要每次轮询连接以查看连接是否仍处于活动状态.这是我用过的代码:
bool SocketConnected(Socket s)
{
bool part1 = s.Poll(1000, SelectMode.SelectRead);
bool part2 = (s.Available == 0);
if (part1 && part2)
return false;
else
return true;
}
Run Code Online (Sandbox Code Playgroud)
它的工作原理如下:
s.Poll 如果返回true
s.Available 返回可用于读取的字节数Aut*_*ico 24
作为禅达写道,这是不错的使用Socket.Poll和Socket.Available,但你需要考虑到插座可能没有在第一时间进行初始化.这是最后一条(我相信)信息,由Socket.Connected酒店提供.修改后的方法版本如下所示:
static bool IsSocketConnected(Socket s)
{
return !((s.Poll(1000, SelectMode.SelectRead) && (s.Available == 0)) || !s.Connected);
/* The long, but simpler-to-understand version:
bool part1 = s.Poll(1000, SelectMode.SelectRead);
bool part2 = (s.Available == 0);
if ((part1 && part2 ) || !s.Connected)
return false;
else
return true;
*/
}
Run Code Online (Sandbox Code Playgroud)
Pau*_*ner 15
该Socket.Connected属性将告诉您套接字是否认为它已连接.它实际上反映了在套接字上执行的最后一次发送/接收操作的状态.
如果套接字已被您自己的操作关闭(处理套接字,调用方法断开连接),Socket.Connected将返回false.如果套接字已通过其他方式断开连接,则该属性将返回,true直到您下次尝试发送或接收信息为止,此时将抛出SocketException或ObjectDisposedException将被抛出.
您可以在发生异常后检查属性,但之前不可靠.
tos*_*-cx 10
如果您拔掉网络电缆,接受的答案似乎不起作用。或者服务器崩溃。或者你的路由器崩溃了。或者,如果您忘记支付互联网账单。设置 TCP 保持活动选项以获得更好的可靠性。
public static class SocketExtensions
{
public static void SetSocketKeepAliveValues(this Socket instance, int KeepAliveTime, int KeepAliveInterval)
{
//KeepAliveTime: default value is 2hr
//KeepAliveInterval: default value is 1s and Detect 5 times
//the native structure
//struct tcp_keepalive {
//ULONG onoff;
//ULONG keepalivetime;
//ULONG keepaliveinterval;
//};
int size = Marshal.SizeOf(new uint());
byte[] inOptionValues = new byte[size * 3]; // 4 * 3 = 12
bool OnOff = true;
BitConverter.GetBytes((uint)(OnOff ? 1 : 0)).CopyTo(inOptionValues, 0);
BitConverter.GetBytes((uint)KeepAliveTime).CopyTo(inOptionValues, size);
BitConverter.GetBytes((uint)KeepAliveInterval).CopyTo(inOptionValues, size * 2);
instance.IOControl(IOControlCode.KeepAliveValues, inOptionValues, null);
}
}
// ...
Socket sock;
sock.SetSocketKeepAliveValues(2000, 1000);
Run Code Online (Sandbox Code Playgroud)
时间值设置自上次发送数据以来的超时时间。然后它尝试发送和接收一个保持活动的数据包。如果失败,它会在确定连接失效之前指定的时间间隔内重试 10 次(自 Vista AFAIK 以来的硬编码次数)。
因此,上述值将导致 2+10*1 = 12 秒的检测。之后,套接字上的任何读取/写入/轮询操作都应该失败。
我根据此 MSDN文章提出了一种扩展方法。这样可以确定套接字是否仍然连接。
public static bool IsConnected(this Socket client)
{
bool blockingState = client.Blocking;
try
{
byte[] tmp = new byte[1];
client.Blocking = false;
client.Send(tmp, 0, 0);
return true;
}
catch (SocketException e)
{
// 10035 == WSAEWOULDBLOCK
if (e.NativeErrorCode.Equals(10035))
{
return true;
}
else
{
return false;
}
}
finally
{
client.Blocking = blockingState;
}
}
Run Code Online (Sandbox Code Playgroud)
public static class SocketExtensions
{
private const int BytesPerLong = 4; // 32 / 8
private const int BitsPerByte = 8;
public static bool IsConnected(this Socket socket)
{
try
{
return !(socket.Poll(1000, SelectMode.SelectRead) && socket.Available == 0);
}
catch (SocketException)
{
return false;
}
}
/// <summary>
/// Sets the keep-alive interval for the socket.
/// </summary>
/// <param name="socket">The socket.</param>
/// <param name="time">Time between two keep alive "pings".</param>
/// <param name="interval">Time between two keep alive "pings" when first one fails.</param>
/// <returns>If the keep alive infos were succefully modified.</returns>
public static bool SetKeepAlive(this Socket socket, ulong time, ulong interval)
{
try
{
// Array to hold input values.
var input = new[]
{
(time == 0 || interval == 0) ? 0UL : 1UL, // on or off
time,
interval
};
// Pack input into byte struct.
byte[] inValue = new byte[3 * BytesPerLong];
for (int i = 0; i < input.Length; i++)
{
inValue[i * BytesPerLong + 3] = (byte)(input[i] >> ((BytesPerLong - 1) * BitsPerByte) & 0xff);
inValue[i * BytesPerLong + 2] = (byte)(input[i] >> ((BytesPerLong - 2) * BitsPerByte) & 0xff);
inValue[i * BytesPerLong + 1] = (byte)(input[i] >> ((BytesPerLong - 3) * BitsPerByte) & 0xff);
inValue[i * BytesPerLong + 0] = (byte)(input[i] >> ((BytesPerLong - 4) * BitsPerByte) & 0xff);
}
// Create bytestruct for result (bytes pending on server socket).
byte[] outValue = BitConverter.GetBytes(0);
// Write SIO_VALS to Socket IOControl.
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
socket.IOControl(IOControlCode.KeepAliveValues, inValue, outValue);
}
catch (SocketException)
{
return false;
}
return true;
}
}
Run Code Online (Sandbox Code Playgroud)