一、网上常用方法
1、当Socket.Conneted == false时,调用如下函数进行判断

此处)折叠或打开

1. /// <summary>
2. /// 当socket.connected为false时,进一步确定下当前连接状态
3. /// </summary>
4. /// <returns></returns>
5. private bool IsSocketConnected()
6. {
7. #region remarks
8. /********************************************************************************************
9. 
				     * 当Socket.Conneted为false时, 如果您需要确定连接的当前状态,请进行非阻塞、零字节的 Send 调用。
10. 
				     * 如果该调用成功返回或引发 WAEWOULDBLOCK 错误代码 (10035),则该套接字仍然处于连接状态; 
11. 
				     * 否则,该套接字不再处于连接状态。
12. 
				     * 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
13. 
				    ********************************************************************************************/
14. #endregion
15. 
16. #region 过程
17. // This is how you can determine whether a socket is still connected.
18. bool connectState = true;
19. bool blockingState = socket.Blocking;
20. try
21. {
22. byte[] tmp = new byte[1];
23. 
24. socket.Blocking = false;
25. socket.Send(tmp, 0, 0);
26. //Console.WriteLine("Connected!");
27. = true; //若Send错误会跳去执行catch体,而不会执行其try体里其之后的代码
28. }
29. catch (SocketException e)
30. {
31. // 10035 == WSAEWOULDBLOCK
32. if (e.NativeErrorCode.Equals(10035))
33. {
34. //Console.WriteLine("Still Connected, but the Send would block");
35. = true;
36. }
37. 
38. else
39. {
40. //Console.WriteLine("Disconnected: error code {0}!", e.NativeErrorCode);
41. = false;
42. }
43. }
44. finally
45. {
46. socket.Blocking = blockingState;
47. }
48. 
49. //Console.WriteLine("Connected: {0}", client.Connected);
50. return connectState;
51. #endregion
52. }

2、根据socket.poll判断

此处)折叠或打开

1. /// <summary>
2. /// 另一种判断connected的方法,但未检测对端网线断开或ungraceful的情况
3. /// </summary>
4. /// <param name="s"></param>
5. /// <returns></returns>
6. static bool IsSocketConnected(Socket s)
7. {
8. #region remarks
9. /* As zendar wrote, it is 
nice to use the Socket.Poll and Socket.Available, but you need to take 
into conside                ration 
10. 
				             * that the socket might not have been initialized in the first place. 
11. 
				             * This is the last (I believe) piece of information and it is supplied by the Socket.Connected property. 
12. 
				             * The revised version of the method would looks something like this: 
13. 
				             * 
from:http://stackoverflow.com/questions/2661764/how-to-check-if-a-
socket-is-connected-disconnected-in-c       */
14. #endregion
15. 
16. #region 过程
17. 
18. return !((s.Poll(1000, SelectMode.SelectRead) && (s.Available == 0)) || !s.Connected);
19. 
20. /* The long, but simpler-to-understand version:
21. 
22. 
				                    bool part1 = s.Poll(1000, SelectMode.SelectRead);
23. 
				                    bool part2 = (s.Available == 0);
24. 
				                    if ((part1 && part2 ) || !s.Connected)
25. 
				                        return false;
26. 
				                    else
27. 
				                        return true;
28. 
29. 
				            */
30. #endregion
31. }

总结:--1--此两种方法出处可在函数体中的remark中找到链接
         --2--此两种方法适用于对端正常关闭socket下的本地socket状态检测,在非正常关闭如断电、拔网线的情况下不起作用
               因为Socket.Conneted存在bug,详见.Net Bugs
二、支持物理断线重连功能的类

        利用BeginReceive + KeepAlive实现物理断线重连,初步测验了一下,正常。(部分代码参考帖子#26及blog在C#中利用keep-alive处理socket网络异常断开)
        Keep-Alive机制的介绍请看TCP Keepalive HOWTO         以此备忘,同时希望能帮助到有需要的同学。

此处)折叠或打开

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using System.Text;
    5. using System.Net.Sockets;
    6. using System.Net;
    7. using System.Threading;
    8. 
    9. namespace MySocket
    10. {
    11. public class Socket_wrapper
    12. {
    13. //委托
    14. private delegate void delSocketDataArrival(byte[] data);
    15. static delSocketDataArrival socketDataArrival = socketDataArrivalHandler;
    16. 
    17. private delegate void delSocketDisconnected();
    18. static delSocketDisconnected socketDisconnected = socketDisconnectedHandler;
    19. 
    20. public static Socket theSocket = null;
    21. private static string remoteHost = "192.168.1.71";
    22. private static int remotePort = 6666;
    23. 
    24. private static String SockErrorStr = null;
    25. private static ManualResetEvent TimeoutObject = new ManualResetEvent(false);
    26. private static Boolean IsconnectSuccess = false; //异步连接情况,由异步连接回调函数置位
    27. private static object lockObj_IsConnectSuccess = new object();
    28. 
    29. /// <summary>
    30. /// 构造函数
    31. /// </summary>
    32. /// <param name="strIp"></param>
    33. /// <param name="iPort"></param>
    34. public Socket_wrapper(string strIp, int iPort)
    35. {
    36. = strIp;
    37. = iPort;
    38. }
    39. 
    40. /// <summary>
    41. /// 设置心跳
    42. /// </summary>
    43. private static void SetXinTiao()
    44. {
    45. //byte[] inValue = new byte[] { 1, 0, 0, 0, 0x20, 0x4e, 0, 0, 0xd0, 0x07, 0, 0 };// 首次探测时间20 秒, 间隔侦测时间2 秒
    46. byte[] inValue = new byte[] { 1, 0, 0, 0, 0x88, 0x13, 0, 0, 0xd0, 0x07, 0, 0 };// 首次探测时间5 秒, 间隔侦测时间2 秒
    47. .IOControl(IOControlCode.KeepAliveValues, inValue, null);
    48. }
    49. 
    50. /// <summary>
    51. /// 创建套接字+异步连接函数
    52. /// </summary>
    53. /// <returns></returns>
    54. private static bool socket_create_connect()
    55. {
    56. IPAddress ipAddress = IPAddress.Parse(remoteHost);
    57. IPEndPoint remoteEP = new IPEndPoint(ipAddress, remotePort);
    58. = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    59. .SendTimeout = 1000;
    60. 
    61. ();//设置心跳参数
    62. 
    63. #region 异步连接代码
    64. 
    65. .Reset(); //复位timeout事件
    66. try
    67. {
    68. .BeginConnect(remoteEP, connectedCallback, theSocket);
    69. }
    70. catch (Exception err)
    71. {
    72. = err.ToString();
    73. return false;
    74. }
    75. if (TimeoutObject.WaitOne(10000, false))//直到timeout,或者TimeoutObject.set()
    76. {
    77. if (IsconnectSuccess)
    78. {
    79. return true;
    80. }
    81. else
    82. {
    83. return false;
    84. }
    85. }
    86. else
    87. {
    88. = "Time Out";
    89. return false;
    90. }
    91. #endregion
    92. }
    93. 
    94. /// <summary>
    95. /// 同步receive函数
    96. /// </summary>
    97. /// <param name="readBuffer"></param>
    98. /// <returns></returns>
    99. public string socket_receive(byte[] readBuffer)
    100. {
    101. try
    102. {
    103. if (theSocket == null)
    104. {
    105. ();
    106. }
    107. else if (!theSocket.Connected)
    108. {
    109. if (!IsSocketConnected())
    110. ();
    111. }
    112. 
    113. int bytesRec = theSocket.Receive(readBuffer);
    114. 
    115. if (bytesRec == 0)
    116. {
    117. //warning 0 bytes received
    118. }
    119. return Encoding.ASCII.GetString(readBuffer, 0, bytesRec);
    120. }
    121. catch (SocketException se)
    122. {
    123. //print se.ErrorCode
    124. throw;
    125. }
    126. }
    127. 
    128. /// <summary>
    129. /// 同步send函数
    130. /// </summary>
    131. /// <param name="sendMessage"></param>
    132. /// <returns></returns>
    133. public bool socket_send(string sendMessage)
    134. {
    135. if (checkSocketState())
    136. {
    137. return SendData(sendMessage);
    138. }
    139. return false;
    140. }
    141. 
    142. /// <summary>
    143. /// 断线重连函数
    144. /// </summary>
    145. /// <returns></returns>
    146. private static bool Reconnect()
    147. {
    148. //关闭socket
    149. .Shutdown(SocketShutdown.Both);
    150. 
    151. .Disconnect(true);
    152. = false;
    153. 
    154. .Close();
    155. 
    156. //创建socket
    157. return socket_create_connect();
    158. }
    159. 
    160. /// <summary>
    161. /// 当socket.connected为false时,进一步确定下当前连接状态
    162. /// </summary>
    163. /// <returns></returns>
    164. private bool IsSocketConnected()
    165. {
    166. #region remarks
    167. /********************************************************************************************
    168. 
    				             * 当Socket.Conneted为false时, 如果您需要确定连接的当前状态,请进行非阻塞、零字节的 Send 调用。
    169. 
    				             * 如果该调用成功返回或引发 WAEWOULDBLOCK 错误代码 (10035),则该套接字仍然处于连接状态; 
    170. 
    				             * 否则,该套接字不再处于连接状态。
    171. 
    				             * 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
    172. 
    				            ********************************************************************************************/
    173. #endregion
    174. 
    175. #region 过程
    176. // This is how you can determine whether a socket is still connected.
    177. bool connectState = true;
    178. bool blockingState = theSocket.Blocking;
    179. try
    180. {
    181. byte[] tmp = new byte[1];
    182. 
    183. .Blocking = false;
    184. .Send(tmp, 0, 0);
    185. //Console.WriteLine("Connected!");
    186. = true; //若Send错误会跳去执行catch体,而不会执行其try体里其之后的代码
    187. }
    188. catch (SocketException e)
    189. {
    190. // 10035 == WSAEWOULDBLOCK
    191. if (e.NativeErrorCode.Equals(10035))
    192. {
    193. //Console.WriteLine("Still Connected, but the Send would block");
    194. = true;
    195. }
    196. 
    197. else
    198. {
    199. //Console.WriteLine("Disconnected: error code {0}!", e.NativeErrorCode);
    200. = false;
    201. }
    202. }
    203. finally
    204. {
    205. .Blocking = blockingState;
    206. }
    207. 
    208. //Console.WriteLine("Connected: {0}", client.Connected);
    209. return connectState;
    210. #endregion
    211. }
    212. 
    213. /// <summary>
    214. /// 另一种判断connected的方法,但未检测对端网线断开或ungraceful的情况
    215. /// </summary>
    216. /// <param name="s"></param>
    217. /// <returns></returns>
    218. public static bool IsSocketConnected(Socket s)
    219. {
    220. #region remarks
    221. /* As zendar wrote, it is nice to use the Socket.Poll and Socket.Available, but you need to take into consideration 
    222. 
    				             * that the socket might not have been initialized in the first place. 
    223. 
    				             * This is the last (I believe) piece of information and it is supplied by the Socket.Connected property. 
    224. 
    				             * The revised version of the method would looks something like this: 
    225. 
    				             * 
    from:http://stackoverflow.com/questions/2661764/how-to-check-if-a-
    socket-is-connected-disconnected-in-c       */
    226. #endregion
    227. 
    228. #region 过程
    229. 
    230. if (s == null)
    231. return false;
    232. return !((s.Poll(1000, SelectMode.SelectRead) && (s.Available == 0)) || !s.Connected);
    233. 
    234. /* The long, but simpler-to-understand version:
    235. 
    236. 
    				                    bool part1 = s.Poll(1000, SelectMode.SelectRead);
    237. 
    				                    bool part2 = (s.Available == 0);
    238. 
    				                    if ((part1 && part2 ) || !s.Connected)
    239. 
    				                        return false;
    240. 
    				                    else
    241. 
    				                        return true;
    242. 
    243. 
    				            */
    244. #endregion
    245. }
    246. 
    247. /// <summary>
    248. /// 异步连接回调函数
    249. /// </summary>
    250. /// <param name="iar"></param>
    251. static void connectedCallback(IAsyncResult iar)
    252. {
    253. #region <remarks>
    254. /// 1、置位IsconnectSuccess
    255. #endregion </remarks>
    256. 
    257. lock (lockObj_IsConnectSuccess)
    258. {
    259. Socket client = (Socket)iar.AsyncState;
    260. try
    261. {
    262. .EndConnect(iar);
    263. = true;
    264. (); //开始KeppAlive检测
    265. }
    266. catch (Exception e)
    267. {
    268. //Console.WriteLine(e.ToString());
    269. = e.ToString();
    270. = false;
    271. }
    272. finally
    273. {
    274. .Set();
    275. }
    276. }
    277. }
    278. 
    279. /// <summary>
    280. /// 开始KeepAlive检测函数
    281. /// </summary>
    282. private static void StartKeepAlive()
    283. {
    284. .BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(OnReceiveCallback), theSocket);
    285. }
    286. 
    287. /// <summary>
    288. /// BeginReceive回调函数
    289. /// </summary>
    290. static byte[] buffer = new byte[1024];
    291. private static void OnReceiveCallback(IAsyncResult ar)
    292. {
    293. try
    294. {
    295. Socket peerSock = (Socket)ar.AsyncState;
    296. int BytesRead = peerSock.EndReceive(ar);
    297. if (BytesRead > 0)
    298. {
    299. byte[] tmp = new byte[BytesRead];
    300. Array.ConstrainedCopy(buffer, 0, tmp, 0, BytesRead);
    301. if (socketDataArrival != null)
    302. {
    303. (tmp);
    304. }
    305. }
    306. else//对端gracefully关闭一个连接
    307. {
    308. if (theSocket.Connected)//上次socket的状态
    309. {
    310. if (socketDisconnected != null)
    311. {
    312. //1-重连
    313. ();
    314. //2-退出,不再执行BeginReceive
    315. return;
    316. }
    317. }
    318. }
    319. //此处buffer似乎要清空--待实现 zq
    320. .BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(OnReceiveCallback), theSocket);
    321. }
    322. catch (Exception ex)
    323. {
    324. if (socketDisconnected != null)
    325. {
    326. (); //Keepalive检测网线断开引发的异常在这里捕获
    327. return;
    328. }
    329. }
    330. }
    331. 
    332. /// <summary>
    333. /// 异步收到消息处理器
    334. /// </summary>
    335. /// <param name="data"></param>
    336. private static void socketDataArrivalHandler(byte[] data)
    337. {
    338. }
    339. 
    340. /// <summary>
    341. /// socket由于连接中断(软/硬中断)的后续工作处理器
    342. /// </summary>
    343. private static void socketDisconnectedHandler()
    344. {
    345. ();
    346. }
    347. 
    348. /// <summary>
    349. /// 检测socket的状态
    350. /// </summary>
    351. /// <returns></returns>
    352. public static bool checkSocketState()
    353. {
    354. try
    355. {
    356. if (theSocket == null)
    357. {
    358. return socket_create_connect();
    359. }
    360. else if (IsconnectSuccess)
    361. {
    362. return true;
    363. }
    364. else//已创建套接字,但未connected
    365. {
    366. #region 异步连接代码
    367. 
    368. .Reset(); //复位timeout事件
    369. try
    370. {
    371. IPAddress ipAddress = IPAddress.Parse(remoteHost);
    372. IPEndPoint remoteEP = new IPEndPoint(ipAddress, remotePort);
    373. .BeginConnect(remoteEP, connectedCallback, theSocket);
    374. 
    375. ();//设置心跳参数
    376. }
    377. catch (Exception err)
    378. {
    379. = err.ToString();
    380. return false;
    381. }
    382. if (TimeoutObject.WaitOne(2000, false))//直到timeout,或者TimeoutObject.set()
    383. {
    384. if (IsconnectSuccess)
    385. {
    386. return true;
    387. }
    388. else
    389. {
    390. return false;
    391. }
    392. }
    393. else
    394. {
    395. = "Time Out";
    396. return false;
    397. }
    398. 
    399. #endregion
    400. }
    401. 
    402. }
    403. catch (SocketException se)
    404. {
    405. = se.ToString();
    406. return false;
    407. }
    408. }
    409. 
    410. 
    411. /// <summary>
    412. /// 同步发送
    413. /// </summary>
    414. /// <param name="dataStr"></param>
    415. /// <returns></returns>
    416. public static bool SendData(string dataStr)
    417. {
    418. bool result = false;
    419. if (dataStr == null || dataStr.Length < 0)
    420. return result;
    421. try
    422. {
    423. byte[] cmd = Encoding.Default.GetBytes(dataStr);
    424. int n = theSocket.Send(cmd);
    425. if (n < 1)
    426. = false;
    427. }
    428. catch (Exception ee)
    429. {
    430. = ee.ToString();
    431. = false;
    432. }
    433. return result;
    434. }
    435. }
    436. }