一、网上常用方法

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实现物理断线重连,初步测验了一下,正常。(部分

代码参考帖子#26blog在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 = new byte[1]; theSocket.Blocking = false;
theSocket.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
{
theSocket.Blocking = blockingState;
} //Console.WriteLine("Connected: {0}", client.Connected);
return connectState;
#endregion
} /// /// 另一种判断connected的方法,但未检测对端网线断开或ungraceful的情况
///
///
///
public 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 consideration
* 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 过程 if (s == null)
return false;
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
} /// /// 异步连接回调函数
///
///
static void connectedCallback(IAsyncResult iar)
{
#region <remarks>
/// 1、置位IsconnectSuccess
#endregion </remarks> lock (lockObj_IsConnectSuccess)
{
Socket client = (Socket)iar.AsyncState;
try
{
client.EndConnect(iar);
IsconnectSuccess = true;
StartKeepAlive(); //开始KeppAlive检测
}
catch (Exception e)
{
//Console.WriteLine(e.ToString());
SockErrorStr = e.ToString();
IsconnectSuccess = false;
}
finally
{
TimeoutObject.Set();
}
}
} /// /// 开始KeepAlive检测函数
///
private static void StartKeepAlive()
{
theSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(OnReceiveCallback), theSocket);
} /// /// BeginReceive回调函数
///
static byte[] buffer = new byte[1024];
private static void OnReceiveCallback(IAsyncResult ar)
{
try
{
Socket peerSock = (Socket)ar.AsyncState;
int BytesRead = peerSock.EndReceive(ar);
if (BytesRead > 0)
{
byte[] tmp = new byte[BytesRead];
Array.ConstrainedCopy(buffer, 0, tmp, 0, BytesRead);
if (socketDataArrival != null)
{
socketDataArrival(tmp);
}
}
else//对端gracefully关闭一个连接
{
if (theSocket.Connected)//上次socket的状态
{
if (socketDisconnected != null)
{
//1-重连
socketDisconnected();
//2-退出,不再执行BeginReceive
return;
}
}
}
//此处buffer似乎要清空--待实现 zq
theSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(OnReceiveCallback), theSocket);
}
catch (Exception ex)
{
if (socketDisconnected != null)
{
socketDisconnected(); //Keepalive检测网线断开引发的异常在这里捕获
return;
}
}
} /// /// 异步收到消息处理器
///
///
private static void socketDataArrivalHandler(byte[] data)
{
} /// /// socket由于连接中断(软/硬中断)的后续工作处理器
///
private static void socketDisconnectedHandler()
{
Reconnect();
} /// /// 检测socket的状态
///
///
public static bool checkSocketState()
{
try
{
if (theSocket == null)
{
return socket_create_connect();
}
else if (IsconnectSuccess)
{
return true;
}
else//已创建套接字,但未connected
{
#region 异步连接代码 TimeoutObject.Reset(); //复位timeout事件
try
{
IPAddress ipAddress = IPAddress.Parse(remoteHost);
IPEndPoint remoteEP = new IPEndPoint(ipAddress, remotePort);
theSocket.BeginConnect(remoteEP, connectedCallback, theSocket); SetXinTiao();//设置心跳参数
}
catch (Exception err)
{
SockErrorStr = err.ToString();
return false;
}
if (TimeoutObject.WaitOne(2000, false))//直到timeout,或者TimeoutObject.set()
{
if (IsconnectSuccess)
{
return true;
}
else
{
return false;
}
}
else
{
SockErrorStr = "Time Out";
return false;
} #endregion
} }
catch (SocketException se)
{
SockErrorStr = se.ToString();
return false;
}
} /// /// 同步发送
///
///
///
public static bool SendData(string dataStr)
{
bool result = false;
if (dataStr == null || dataStr.Length < 0)
return result;
try
{
byte[] cmd = Encoding.Default.GetBytes(dataStr);
int n = theSocket.Send(cmd);
if (n < 1)
result = false;
}
catch (Exception ee)
{
SockErrorStr = ee.ToString();
result = false;
}
return result;
}
}
}
转自 https://blog.csdn.net/thebestleo/article/details/52354126

C#之Socket断线重连的更多相关文章

  1. android java socket断线重连

    android java socket断线重连 thread = new Thread(new Runnable() { @Override public void run() { while (tr ...

  2. socket 断线重连

    send发送数据时,发送失败,进行如下重连处理: ) < )//serbuf中有数据可以发送才会执行这条语句 { printf("serial to tcp send msg erro ...

  3. 关于socket tcp 断线重连

    这个问题困扰过我几次,都没有来得及研究,今天研究一下. 首先写一个最简易的socket tcp程序,连接成功后再关闭服务器然后再用客户端各种操作看是什么情况 测试表明 (1)客户端已经连接,当服务端关 ...

  4. netty4 断线重连

    转载:http://www.tuicool.com/articles/B7RzMbY 一 实现心跳检测 原理:当服务端每隔一段时间就会向客户端发送心跳包,客户端收到心跳包后同样也会回一个心跳包给服务端 ...

  5. 浅谈IM软件client的断线重连、心跳和长在线

    版权声明:原创文章,未经博主同意禁止转载.欢迎点击头像上方"郭晓东的专栏"查看专栏 https://blog.csdn.net/hherima/article/details/27 ...

  6. Mina.Net实现的断线重连

    using Mina.Filter.Codec; using Mina.Filter.Codec.TextLine; using System; using System.Collections.Ge ...

  7. Mina 断线重连

    Mina 断线重连 定义:这里讨论的Mina 断线重连是指使用mina作为客户端软件,连接其他提供Socket通讯服务的服务器端.Socket服务器可以是Mina提供的服务器,也可以是C++提供的服务 ...

  8. 微信小程序使用原生WebSokcet实现断线重连及数据拼接

    以前做小程序为了应急找了个插件去链接WebSokcet,文章传送门. 回过头在新项目中再次使用时出现了些许问题,不一一赘述.遂决定好好用一下原生的WebSokcet. 一.说明 1.小程序原生的Web ...

  9. Netty学习篇④-心跳机制及断线重连

    心跳检测 前言 客户端和服务端的连接属于socket连接,也属于长连接,往往会存在客户端在连接了服务端之后就没有任何操作了,但还是占用了一个连接:当越来越多类似的客户端出现就会浪费很多连接,netty ...

随机推荐

  1. H5移动端下html上传图片被旋转问题

    iOS下,html方式使用<input type="file">上传图片,图片会被旋转.遇到这个问题js是无法解决的,html也没有相应的解决方案.只能放到后台去处理, ...

  2. Sentry入门

    指令类型: 创建.删除角色: CREATE ROLE sentry_all; droop role admin_role;   角色授权/撤销权限: 数据库级别角色授权 GRANT ALL ON DA ...

  3. Azure SLB + httpd + ILB + HAProxy + Atlas + MySQL

    为了测试一个环境,需要在Azure上搭建高可用的LAMP架构.但要求MySQL的中间件Atlas采用主备的模式.在数据中心一般采用Keepalive+VIP的模式,通过浮动地址对外提供服务. 但在云环 ...

  4. 蓝桥杯 历届试题 PREV-2 打印十字图

    历届试题 打印十字图   时间限制:1.0s   内存限制:256.0MB 小明为某机构设计了一个十字型的徽标(并非红十字会啊),如下所示: 对方同时也需要在电脑dos窗口中以字符的形式输出该标志,并 ...

  5. [转载]rmmod: can't change directory to '/lib/modules': No such file or directory

    转载网址:http://blog.csdn.net/chengwen816/article/details/8781096 在我新移植的kernel(3.4.2)和yaffs2文件中,加载新编译的内核 ...

  6. ov2640数据

    问题部分解决,数据错误的原因是太快了.将0x11->3f  0xd3->7f 哈哈 问题解决 直接降低7670输出频率 调0x11到最大分频比 现在能完整抓拍QVGA的图像 不过就是采集速 ...

  7. L2-013. 红色警报(dfs)

    L2-013. 红色警报 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 战争中保持各个城市间的连通性非常重要.本题要求你编写一 ...

  8. mysql查询最近30天、7天、每天、昨天、上个月的记录

      一些变量说明: add_time为插入的时间 to_days是sql函数,返回的是个天数 data_sub(date,INTERVAL expr type)给指定的日期减去多少天 data()函数 ...

  9. [转]浅谈javascript函数劫持

    转自:Ph4nt0m Security Team 这么多年了,现在学习依然还是有很多收货,向前辈致敬.转载一方面是自己存档一份,另一方面是让更多喜欢安全的人一同学习. ================ ...

  10. 跨数据文件删除flashback database

    Oracle flashback database的使用有一些限制,其中最主要的是flashback database不支持跨数据文件删除闪回和不支持跨数据文件shrink闪回.对于已经删除的数据文件 ...