/// <summary> /// 檢查一個Socket是否可連接 /// </summary> /// <param name="socket"></param> /// <returns></returns> private bool IsConnected(Socket socket) { if (socket == null || socket.Connected == false) { return false; } bool blockingState = socket.Blocking; try { byte[] tmp = new byte[1]; socket.Blocking = false; socket.Send(tmp, 0, 0); return true; } catch (SocketException e) { // 產生 10035 == WSAEWOULDBLOCK 錯誤,說明被阻止了,但是還是連接的 if (e.NativeErrorCode.Equals(10035)) { return true; } else { return false; } } finally { socket.Blocking = blockingState; // 恢復狀態 } }
上面的代碼來自互聯網
原理就是在外面加個timer/task/thread,每隔一段時間,做心跳檢查。如果發送信息失敗表示無法連接,那么我們就可以重連了。
/// <summary> /// 輪詢檢查Socket連接 /// </summary> private void PollingCheckSocket() { _pollingCheckSocketTimer = new System.Threading.Timer((obj) => { if (!_run)//控制timer暫停、恢復用的 { return; } foreach (var hub in _hubs) { //為null或斷開連接時,重連 var connected = this.IsConnected(hub.Socket); if (!connected) { _socketService.Close(hub.Socket); hub.Socket = _socketService.Get(hub); } } }, null, 10000, 15000);//表示10秒后開始檢查,然后每15秒檢查一次 }
我是將socket作為hub的一個屬性。這里是遍歷所有hub,逐一檢查每個hub的socket是否斷開。如果斷開了,先關閉舊的socket,再重連。需要說明的是,這里的重連是新建一個socket連接,舊的socket連接是無法再次連接的。以下是socket輔助類:
public class SocketService { private Logger _logger = LogManager.GetCurrentClassLogger(); /// <summary> /// 獲取socket /// </summary> /// <param name="model"></param> /// <returns></returns> public Socket Get(HubModel model) { try { // 將IP地址字符串轉換為IPAddress對象 IPAddress ip = IPAddress.Parse(model.IP); // 創建終結點EndPoint IPEndPoint endPoint = new IPEndPoint(ip, model.Port); // 創建Socket並連接到服務器 Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // 連接到服務器 socket.Connect(endPoint); return socket; } catch (System.Exception ex) { _logger.Error(string.Format("獲取socket異常,message:{0},stacktrace:{1}", ex.Message, ex.StackTrace)); } return null; } /// <summary> /// 關閉socket /// </summary> /// <param name="socket"></param> public void Close(Socket socket) { if (socket != null) { socket.Close(); socket = null; } } } }