C#之Socket断线和重连
2021-03-10 10:29
标签:read version socket received poi val format 两种 stack 一、网上常用方法 1、当Socket.Conneted == false时,调用如下函数进行判断 2、根据socket.poll判断 总结: 1、此两种方法出处可在函数体中的remark中找到链接 2、此两种方法适用于对端正常关闭socket下的本地socket状态检测,在非正常关闭如断电、拔网线的情况下不起作用因为Socket.Conneted存在bug,详见.Net Bugs 二、支持物理断线重连功能的类 利用BeginReceive + KeepAlive实现物理断线重连,初步测验了一下,正常。(部分代码参考帖子#26及blog在C#中利用keep-alive处理socket网络异常断开) Keep-Alive机制的介绍请看TCP Keepalive HOWTO,以此备忘,同时希望能帮助到有需要的同学。 转载:https://www.cnblogs.com/wzd24/ C#之Socket断线和重连 标签:read version socket received poi val format 两种 stack 原文地址:https://www.cnblogs.com/X-Jonney/p/12698673.html 1 ///
2 /// 当socket.connected为false时,进一步确定下当前连接状态
3 ///
4 ///
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 connectState = 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 connectState = true;
36 }
37
38 else
39 {
40 //Console.WriteLine("Disconnected: error code {0}!", e.NativeErrorCode);
41 connectState = 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 }
1 ///
2 /// 另一种判断connected的方法,但未检测对端网线断开或ungraceful的情况
3 ///
4 ///
5 ///
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 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 ///
30
31 /// 构造函数
32 ///
33 ///
34 ///
35 public Socket_wrapper(string strIp, int iPort)
36 {
37 remoteHost = strIp;
38 remotePort = iPort;
39 }
40
41 ///
42
43 /// 设置心跳
44 ///
45 private static void SetXinTiao()
46 {
47 //byte[] inValue = new byte[] { 1, 0, 0, 0, 0x20, 0x4e, 0, 0, 0xd0, 0x07, 0, 0 };// 首次探测时间20 秒, 间隔侦测时间2 秒
48 byte[] inValue = new byte[] { 1, 0, 0, 0, 0x88, 0x13, 0, 0, 0xd0, 0x07, 0, 0 };// 首次探测时间5 秒, 间隔侦测时间2 秒
49 theSocket.IOControl(IOControlCode.KeepAliveValues, inValue, null);
50 }
51
52 ///
53
54 /// 创建套接字+异步连接函数
55 ///
56 ///
57 private static bool socket_create_connect()
58 {
59 IPAddress ipAddress = IPAddress.Parse(remoteHost);
60 IPEndPoint remoteEP = new IPEndPoint(ipAddress, remotePort);
61 theSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
62 theSocket.SendTimeout = 1000;
63
64 SetXinTiao();//设置心跳参数
65
66 #region 异步连接代码
67
68 TimeoutObject.Reset(); //复位timeout事件
69 try
70 {
71 theSocket.BeginConnect(remoteEP, connectedCallback, theSocket);
72 }
73 catch (Exception err)
74 {
75 SockErrorStr = err.ToString();
76 return false;
77 }
78 if (TimeoutObject.WaitOne(10000, false))//直到timeout,或者TimeoutObject.set()
79 {
80 if (IsconnectSuccess)
81 {
82 return true;
83 }
84 else
85 {
86 return false;
87 }
88 }
89 else
90 {
91 SockErrorStr = "Time Out";
92 return false;
93 }
94 #endregion
95 }
96
97 ///
98
99 /// 同步receive函数
100 ///
101 ///
102 ///
103 public string socket_receive(byte[] readBuffer)
104 {
105 try
106 {
107 if (theSocket == null)
108 {
109 socket_create_connect();
110 }
111 else if (!theSocket.Connected)
112 {
113 if (!IsSocketConnected())
114 Reconnect();
115 }
116
117 int bytesRec = theSocket.Receive(readBuffer);
118
119 if (bytesRec == 0)
120 {
121 //warning 0 bytes received
122 }
123 return Encoding.ASCII.GetString(readBuffer, 0, bytesRec);
124 }
125 catch (SocketException se)
126 {
127 //print se.ErrorCode
128 throw;
129 }
130 }
131
132 ///
133
134 /// 同步send函数
135 ///
136 ///
137 ///
138 public bool socket_send(string sendMessage)
139 {
140 if (checkSocketState())
141 {
142 return SendData(sendMessage);
143 }
144 return false;
145 }
146
147 ///
148
149 /// 断线重连函数
150 ///
151 ///
152 private static bool Reconnect()
153 {
154 //关闭socket
155 theSocket.Shutdown(SocketShutdown.Both);
156
157 theSocket.Disconnect(true);
158 IsconnectSuccess = false;
159
160 theSocket.Close();
161
162 //创建socket
163 return socket_create_connect();
164 }
165
166 ///
167
168 /// 当socket.connected为false时,进一步确定下当前连接状态
169 ///
170 ///
171 private bool IsSocketConnected()
172 {
173 #region remarks
174 /********************************************************************************************
175 * 当Socket.Conneted为false时, 如果您需要确定连接的当前状态,请进行非阻塞、零字节的 Send 调用。
176 * 如果该调用成功返回或引发 WAEWOULDBLOCK 错误代码 (10035),则该套接字仍然处于连接状态;
177 * 否则,该套接字不再处于连接状态。
178 * 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
179 ********************************************************************************************/
180 #endregion
181
182 #region 过程
183 // This is how you can determine whether a socket is still connected.
184 bool connectState = true;
185 bool blockingState = theSocket.Blocking;
186 try
187 {
188 byte[] tmp = new byte[1];
189
190 theSocket.Blocking = false;
191 theSocket.Send(tmp, 0, 0);
192 //Console.WriteLine("Connected!");
193 connectState = true; //若Send错误会跳去执行catch体,而不会执行其try体里其之后的代码
194 }
195 catch (SocketException e)
196 {
197 // 10035 == WSAEWOULDBLOCK
198 if (e.NativeErrorCode.Equals(10035))
199 {
200 //Console.WriteLine("Still Connected, but the Send would block");
201 connectState = true;
202 }
203
204 else
205 {
206 //Console.WriteLine("Disconnected: error code {0}!", e.NativeErrorCode);
207 connectState = false;
208 }
209 }
210 finally
211 {
212 theSocket.Blocking = blockingState;
213 }
214
215 //Console.WriteLine("Connected: {0}", client.Connected);
216 return connectState;
217 #endregion
218 }
219
220 ///
221
222 /// 另一种判断connected的方法,但未检测对端网线断开或ungraceful的情况
223 ///
224 ///
225 ///
226 public static bool IsSocketConnected(Socket s)
227 {
228 #region remarks
229 /* As zendar wrote, it is nice to use the Socket.Poll and Socket.Available, but you need to take into consideration
230 * that the socket might not have been initialized in the first place.
231 * This is the last (I believe) piece of information and it is supplied by the Socket.Connected property.
232 * The revised version of the method would looks something like this:
233 * from:http://stackoverflow.com/questions/2661764/how-to-check-if-a-socket-is-connected-disconnected-in-c */
234 #endregion
235
236 #region 过程
237
238 if (s == null)
239 return false;
240 return !((s.Poll(1000, SelectMode.SelectRead) && (s.Available == 0)) || !s.Connected);
241
242 /* The long, but simpler-to-understand version:
243
244 bool part1 = s.Poll(1000, SelectMode.SelectRead);
245 bool part2 = (s.Available == 0);
246 if ((part1 && part2 ) || !s.Connected)
247 return false;
248 else
249 return true;
250
251 */
252 #endregion
253 }
254
255 ///
256
257 /// 异步连接回调函数
258 ///
259 ///
260 static void connectedCallback(IAsyncResult iar)
261 {
262 #region