一、网上常用方法
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. }