一、网上常用方法
1、当Socket.Conneted == false时,调用如下函数进行判断
///
/// 当socket.connected为false时,进一步确定下当前连接状态
///
///
private bool IsSocketConnected()
{
#region remarks
/********************************************************************************************
* 当Socket.Conneted为false时, 如果您需要确定连接的当前状态,请进行非阻塞、零字节的 Send 调用。
* 如果该调用成功返回或引发 WAEWOULDBLOCK 错误代码 (10035),则该套接字仍然处于连接状态;
* 否则,该套接字不再处于连接状态。
* Depending on http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.connected.aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-2
********************************************************************************************/
#endregion
#region 过程
// This is how you can determine whether a socket is still connected.
bool connectState = true;
bool blockingState = socket.Blocking;
try
{
byte[] tmp = new byte[1];
socket.Blocking = false;
socket.Send(tmp, 0, 0);
//Console.WriteLine("Connected!");
connectState = true; //若Send错误会跳去执行catch体,而不会执行其try体里其之后的代码
}
catch (SocketException e)
{
// 10035 == WSAEWOULDBLOCK
if (e.NativeErrorCode.Equals(10035))
{
//Console.WriteLine("Still Connected, but the Send would block");
connectState = true;
}
else
{
//Console.WriteLine("Disconnected: error code {0}!", e.NativeErrorCode);
connectState = false;
}
}
finally
{
socket.Blocking = blockingState;
}
//Console.WriteLine("Connected: {0}", client.Connected);
return connectState;
#endregion
}
2、根据socket.poll判断
///
/// 另一种判断connected的方法,但未检测对端网线断开或ungraceful的情况
///
///
///
static bool IsSocketConnected(Socket s)
{
#region remarks
/* As zendar wrote, it is nice to use the Socket.Poll and Socket.Available, but you need to take into conside ration
* that the socket might not have been initialized in the first place.
* This is the last (I believe) piece of information and it is supplied by the Socket.Connected property.
* The revised version of the method would looks something like this:
* from:http://stackoverflow.com/questions/2661764/how-to-check-if-a-socket-is-connected-disconnected-in-c */
#endregion
#region 过程
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;
*/
#endregion
}
总结:
1、此两种方法出处可在函数体中的remark中找到链接
2、此两种方法适用于对端正常关闭socket下的本地socket状态检测,在非正常关闭如
断电、拔网线的情况下不起作用因为Socket.Conneted存在bug,详见.Net Bugs
二、支持物理断线重连功能的类
利用BeginReceive + KeepAlive实现物理断线重连,初步测验了一下,正常。(部分
代码参考帖子#26及blog在C#中利用keep-alive处理socket网络异常断开)
Keep-Alive机制的介绍请看TCP Keepalive HOWTO,以此备忘,同时希望能帮助到
有需要的同学。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;
namespace MySocket
{
public class Socket_wrapper
{
//委托
private delegate void delSocketDataArrival(byte[] data);
static delSocketDataArrival socketDataArrival = socketDataArrivalHandler;
private delegate void delSocketDisconnected();
static delSocketDisconnected socketDisconnected = socketDisconnectedHandler;
public static Socket theSocket = null;
private static string remoteHost = "192.168.1.71";
private static int remotePort = 6666;
private static String SockErrorStr = null;
private static ManualResetEvent TimeoutObject = new ManualResetEvent(false);
private static Boolean IsconnectSuccess = false; //异步连接情况,由异步连接回调函数置位
private static object lockObj_IsConnectSuccess = new object();
///
/// 构造函数
///
///
///
public Socket_wrapper(string strIp, int iPort)
{
remoteHost = strIp;
remotePort = iPort;
}
///
/// 设置心跳
///
private static void SetXinTiao()
{
//byte[] inValue = new byte[] { 1, 0, 0, 0, 0x20, 0x4e, 0, 0, 0xd0, 0x07, 0, 0 };// 首次探测时间20 秒, 间隔侦测时间2 秒
byte[] inValue = new byte[] { 1, 0, 0, 0, 0x88, 0x13, 0, 0, 0xd0, 0x07, 0, 0 };// 首次探测时间5 秒, 间隔侦测时间2 秒
theSocket.IOControl(IOControlCode.KeepAliveValues, inValue, null);
}
///
/// 创建套接字+异步连接函数
///
///
private static bool socket_create_connect()
{
IPAddress ipAddress = IPAddress.Parse(remoteHost);
IPEndPoint remoteEP = new IPEndPoint(ipAddress, remotePort);
theSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
theSocket.SendTimeout = 1000;
SetXinTiao();//设置心跳参数
#region 异步连接代码
TimeoutObject.Reset(); //复位timeout事件
try
{
theSocket.BeginConnect(remoteEP, connectedCallback, theSocket);
}
catch (Exception err)
{
SockErrorStr = err.ToString();
return false;
}
if (TimeoutObject.WaitOne(10000, false))//直到timeout,或者TimeoutObject.set()
{
if (IsconnectSuccess)
{
return true;
}
else
{
return false;
}
}
else
{
SockErrorStr = "Time Out";
return false;
}
#endregion
}
///
/// 同步receive函数
///
///
///
public string socket_receive(byte[] readBuffer)
{
try
{
if (theSocket == null)
{
socket_create_connect();
}
else if (!theSocket.Connected)
{
if (!IsSocketConnected())
Reconnect();
}
int bytesRec = theSocket.Receive(readBuffer);
if (bytesRec == 0)
{
//warning 0 bytes received
}
return Encoding.ASCII.GetString(readBuffer, 0, bytesRec);
}
catch (SocketException se)
{
//print se.ErrorCode
throw;
}
}
///
/// 同步send函数
///
///
///
public bool socket_send(string sendMessage)
{
if (checkSocketState())
{
return SendData(sendMessage);
}
return false;
}
///
/// 断线重连函数
///
///
private static bool Reconnect()
{
//关闭socket
theSocket.Shutdown(SocketShutdown.Both);
theSocket.Disconnect(true);
IsconnectSuccess = false;
theSocket.Close();
//创建socket
return socket_create_connect();
}
///
/// 当socket.connected为false时,进一步确定下当前连接状态
///
///
private bool IsSocketConnected()
{
#region remarks
/********************************************************************************************
* 当Socket.Conneted为false时, 如果您需要确定连接的当前状态,请进行非阻塞、零字节的 Send 调用。
* 如果该调用成功返回或引发 WAEWOULDBLOCK 错误代码 (10035),则该套接字仍然处于连接状态;
* 否则,该套接字不再处于连接状态。
* Depending on http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.connected.aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-2
********************************************************************************************/
#endregion
#region 过程
// This is how you can determine whether a socket is still connected.
bool connectState = true;
bool blockingState = theSocket.Blocking;
try
{
byte[] tmp =