在写 C# socket 的时候发现 socket 连接无法设置超时时间,需要15s才能超时返回。百度一下发现也没有实现的比较好的代码。
因此,才有了下面这段 socket 连接超时的代码,这段代码已经应用到实际的项目中,并且运行稳定。
如果你有更好的实现方案可以给我留言。
class Socket2 : IComunication { static IPEndPoint ipe; static byte[] sendBytes = new byte[1400]; static byte[] recBytes = new byte[1400]; volatile static Socket socket = null; static System.Threading.Timer readTimer = null; static int readOverTime; static bool ReadOK; static System.Threading.Timer connectTimer = null; static int connectOverTime; public Socket2() { readTimer = new System.Threading.Timer(OnReadTimeUp, null, Timeout.Infinite, Timeout.Infinite); object obj = Global.Config.Read("ReadOverTime"); if (obj == null || !int.TryParse(obj.ToString(), out readOverTime)) { readOverTime = 3000; } obj = Global.Config.Read("ConnectOverTime"); if (obj == null || !int.TryParse(obj.ToString(), out connectOverTime)) { connectOverTime = 3000; } } private static void OnConnectTimeUp(object obj) { StateObject stateObject = (StateObject)obj; lock (connectTimer) { if (stateObject.socket != null) { stateObject.socket.Close(); stateObject.socket = null; socket = null; } } } private static void OnReadTimeUp(object obj) { ReadOK = false; socket.Close(); } public bool Start() { try { if (socket == null) { string host = Global.Config.Read("DriverIP").ToString(); int port = Convert.ToInt32(Global.Config.Read("DriverPort")); IPAddress ip = IPAddress.Parse(host); ipe = new IPEndPoint(ip, port); socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); socket.DontFragment = false; socket.ExclusiveAddressUse = true; socket.UseOnlyOverlappedIO = false; socket.SendBufferSize = 1500; socket.ReceiveBufferSize = 1500; socket.ReceiveTimeout = readOverTime; socket.SendTimeout = readOverTime; // 设置连接超时计时器 StateObject so = new StateObject(); so.socket = socket; //socket.Connect(ipe); connectTimer = new System.Threading.Timer(OnConnectTimeUp, so, Timeout.Infinite, Timeout.Infinite); connectTimer.Change(connectOverTime, Timeout.Infinite); socket.BeginConnect(ipe, new AsyncCallback(ConnectCallback), so); autoEventConnect.WaitOne(); } return true; } catch (SocketException e) { Global.log.Debug(e); socket.Close(); socket = null; return false; } catch (Exception e) { if (socket != null) { socket.Close(); } socket = null; return false; } } AutoResetEvent autoEventConnect = new AutoResetEvent(false); private void ConnectCallback(IAsyncResult ar) { // Retrieve the socket from the state object. StateObject stateObject = (StateObject)ar.AsyncState; lock (connectTimer) { try { if (stateObject.socket != null) { // Complete the connection. stateObject.socket.EndConnect(ar); connectTimer.Change(Timeout.Infinite, Timeout.Infinite); connectTimer.Dispose(); } } catch (Exception e) { if (stateObject.socket != null) { stateObject.socket.Close(); } stateObject.socket = null; stateObject.reciveBuffer = null; stateObject.sendBuffer = null; stateObject = null; } } autoEventConnect.Set(); } public bool Stop() { if (socket != null) { socket.Close(); } socket = null; return true; } public bool Write() { try { if (socket != null) { buildSendBytes(); socket.NoDelay = true; int n = socket.Send(sendBytes, sendBytes.Length , SocketFlags.None); if (n != sendBytes.Length) { Global.log.Debug("send error 需要发送的字节数 " + "实际发送的字节数" + sendBytes.Length + ":" +n); } return true; } else { return false; } } catch (Exception e) { Global.log.Debug("Error Send"); Global.log.Debug(e); if (socket != null) { socket.Close(); socket = null; } return false; } } public bool Read() { try { if (socket != null) { StateObject so = new StateObject(); so.socket = socket; so.reciveBuffer = recBytes; // 设置读超时计时器 readTimer.Change(readOverTime, Timeout.Infinite); socket.BeginReceive(recBytes, 0, recBytes.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), so); // 接受完成 autoEvent.WaitOne(); readTimer.Change(Timeout.Infinite, Timeout.Infinite); buildRecBytes(); // 需要添加读超时返回 false if (ReadOK == true) { return true; } else { return false; } } else { return false; } } catch (Exception e) { Global.log.Debug(e); return false; } } AutoResetEvent autoEvent = new AutoResetEvent(false); public class StateObject { public Socket socket = null; public byte[] reciveBuffer = null; public byte[] sendBuffer = null; } volatile int bytesRecieved = 0; public void ReceiveCallback(IAsyncResult ar) { StateObject state = null; try { // Retrieve the state object and the client socket // from the asynchronous state object. state = (StateObject)ar.AsyncState; // Read data from the remote device. int bytesRead = state.socket.EndReceive(ar); if (bytesRead > 1400) { Global.log.Debug("bytesRead > 1400 :" + bytesRead); } if (bytesRead > 0) { bytesRecieved += bytesRead; if (bytesRecieved < recBytes.Length) { state.socket.BeginReceive(state.reciveBuffer, bytesRecieved, state.reciveBuffer.Length - bytesRecieved, SocketFlags.None, new AsyncCallback(ReceiveCallback), state); } if (bytesRecieved == recBytes.Length) { bytesRecieved = 0; ReadOK = true; autoEvent.Set(); } } else { state.socket.Close(); state.socket = null; socket = null; state.reciveBuffer = null; state.sendBuffer = null; state = null; ReadOK = false; autoEvent.Set(); } } catch (Exception e) { Global.log.Debug("Error Recieve"); Global.log.Debug(e); if (state.socket != null) { state.socket.Close(); state.socket = null; socket = null; } state.reciveBuffer = null; state.sendBuffer = null; state = null; ReadOK = false; autoEvent.Set(); } } public bool ReadArray() { throw new NotImplementedException(); } public bool WriteArray() { throw new NotImplementedException(); } }