首页 > TCP异步编程如何快速获知网络连接中断?

TCP异步编程如何快速获知网络连接中断?

小弟最近在写TCP异步编程的程序,发送和接受都是用的回调函数的形式,遇到一个头疼的问题就是在考虑网络连接突然中断的情况时,程序往往需要在客户端发送一条消息之后15秒左右的时间,才会检测到连接中止,捕获connectionAborted异常。那么大家平常都是怎么做的呢


using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace _10_TCP模块化编程
{
    class ObjectState
    {
        public Socket client;

        public MyTcp obj;
        public const int BufferSize = 256;
        // Receive buffer.     
        public byte[] buffer = new byte[BufferSize];
        // Received data string.     
        public StringBuilder sb = new StringBuilder();
    }
    class MyTcp
    {
        public delegate void dReceiver(object sender, string b);
        public event dReceiver receive;
        public Socket WebHabor;
        //private bool connected;
        public MyTcp(IPEndPoint iep, dReceiver dEventCall)
        {
            
            //接收消息的委托;
            receive += dEventCall;
            //创建socket连接;
            WebHabor = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            ObjectState obs = new ObjectState();
            obs.obj = this;
            obs.client = WebHabor;
            WebHabor.BeginConnect(iep, new AsyncCallback(ConnectCallback), obs);
            //connected = WebHabor.Connected ? true : false;
            Thread.Sleep(10);
            if (WebHabor.Connected == true)
            {
                Receive();
            }
            else
            {
                Program.postLog("连接失败,请检查ip和port");
            }
        }
        public static void ExceptionSolver(SocketException sep)
        {
            switch (sep.SocketErrorCode)
            {
                case SocketError.NotConnected:
                    //捕获ip地址输入错误的情况;
                    Program.postLog("不存在网络连接");
                    break;

                case SocketError.ConnectionAborted:
                    //在这里处理频繁出现的错误,
                    //比如IP不对,网线没插
                    Program.postLog("连接中止");
                    break;
                case SocketError.ConnectionRefused:
                    //远程主机正在主动拒绝连接;可能是连接的时候ip或port写错了;
                    Program.postLog("对方不接受连接,更可能是port的原因");
                    break;
                case SocketError.HostUnreachable:
                    Program.postLog("连接目标不可达");
                    break;
                case SocketError.TimedOut:
                    //尝试连接ip超时;
                    Program.postLog("尝试连接ip超时,更可能是ip的原因");
                    break;
                default:
                    Program.postLog("捕获到" + sep.SocketErrorCode);
                    //这里直接报错,如果调试的时候出现这里的错误比较多,就移到上面解决,一般问题都是从来不出的
                    break;

            }
        }


        public void Send(byte[] dataToSend,int byteCount)
        {

            try
            {
                WebHabor.BeginSend(dataToSend, 0, byteCount, 0, new AsyncCallback(SendCallback), WebHabor);
                //System.Threading.Thread.Sleep(10);//为了让其它线程跑起来;
            }
            catch (SocketException sep)
            {
                Program.postLog("在Send这里");
                ExceptionSolver(sep);
            }
        }
        public void Receive()
        {
        
            byte[] buffer = new byte[256];

            ObjectState obs = new ObjectState();
            obs.obj = this;//这个传的是MyTcp;
            obs.client = WebHabor;

            try
            {
                WebHabor.BeginReceive(obs.buffer, 0, ObjectState.BufferSize, 0, new AsyncCallback(ReceiveCallback), obs);
            }
            catch (SocketException sep)
            {
                Program.postLog("在reveive这里");
                ExceptionSolver(sep);
            }
            //receive.Invoke(this, buffer);
        }
       
        

        //beginConnect的回调函数;
        private static void ConnectCallback(IAsyncResult ar)
        {
            ObjectState obs = (ObjectState)ar.AsyncState;
            try
            {
                // Retrieve the socket from the state object.     
                
                Socket client = obs.client;
                // Complete the connection.     
                client.EndConnect(ar);
                //Console.WriteLine("Socket connected to {0}", client.RemoteEndPoint.ToString());
                //连上就连上吧就不发数据了
                //MessageBox.Show("Socket connected to " + client.RemoteEndPoint.ToString());
                // Signal that the connection has been made.     
                //connectDone.Set();
            }
            catch (SocketException sep)
            {
                //Console.WriteLine(e.ToString());
                //MessageBox.Show("connect回调函数出错了" + e.ToString());
                /*********************************************************************
                 * 
                 * 此处需要考察一下连接失败的异常情况。
                 * 
                 *********************************************************************/
                //obs.obj.connected = false;
                Program.postLog("在ConnectCallback这里");
                ExceptionSolver(sep);
            }

        }
        private static void SendCallback(IAsyncResult ar)
        {
            try
            {
                // Retrieve the socket from the state object.     
                Socket client = (Socket)ar.AsyncState;
                //System.Threading.Thread.Sleep(10);//为了让其它线程跑起来;
                // Complete sending the data to the remote device.     
                int bytesSent = client.EndSend(ar);
                Program.postLog("本次发送" + bytesSent + "个字节");
                //Console.WriteLine("Sent {0} bytes to server.", bytesSent);
                //MessageBox.Show("Sent " + bytesSent + " bytes to server.");
                // Signal that all bytes have been sent.     
                //sendDone.Set();
            }
            catch (SocketException sep)
            {
                //MessageBox.Show("Send回调函数出错了" + e.ToString());
                /*********************************************************************
                 * 
                 * 此处需要考察一下发送失败的异常情况。
                 * 
                 *********************************************************************/
                Program.postLog("在SendCallback这里");
                ExceptionSolver(sep);
            }
        }
        private static void ReceiveCallback(IAsyncResult ar)
        {
            //byte[] buffer = new byte[256];
            try
            {
                // Retrieve the state object and the client socket     
                // from the asynchronous state object.     
                //StateObject state = (StateObject)ar.AsyncState;
                //Socket client = state.workSocket;
                // Read data from the remote device.    
                ObjectState objs = (ObjectState)ar.AsyncState;

                Socket client = objs.client;
                int bytesRead = client.EndReceive(ar);
                if (bytesRead > 0)
                {
                    
                    // There might be more data, so store the data received so far.     
                    string getMsg = Encoding.ASCII.GetString(objs.buffer, 0, bytesRead);

                    //Console.WriteLine("新得到的数据是" + getMsg + "呵呵");
                    //MessageBox.Show("新得到的数据是" + getMsg);
                    string msg=Encoding.Default.GetString(objs.buffer, 0, bytesRead);

                    Program.postLog(msg);
                    //objs.obj.receive.Invoke(objs.obj, msg);//因为这是静态函数,这个objs.obj实际是MyTcp实例。
                    //MessageBox.Show(bytesRead.ToString() + "更新数据后:" + state.sb.ToString());
                    // Get the rest of the data.     
                    client.BeginReceive(objs.buffer, 0, objs.buffer.Length, 0, new AsyncCallback(ReceiveCallback), objs);
                    
                }
                else
                {
                    //接到0字节说明对方主动断开了连接;
                    Program.postLog("对方主动断开连接");
                }
            }
            catch (SocketException sep)
            {
                //MessageBox.Show("Receive回调函数出错了" + e.ToString());
                /*********************************************************************
                 * 
                 * 此处需要考察一下接收失败的异常情况。
                 * 
                 *********************************************************************/
                Program.postLog("在ReceiveCallback这里");
                ExceptionSolver(sep);
            }
        }
    }
}


自己单独写一个线程来发送特定的存活验证数据,然后在接收端处理的时候,添加对这种数据的处理。以前写过非常简单的一篇文章:
JAVA ANDROID SOCKET通信检测(SERVER)连接是否断开


如果要求比较严格的话,你试试加入心跳包的机制呢?


心跳包+timeout
程序上你就算保证了链接没有断开,你仍旧需要保证对方程序是否出现异常,所以在跨服务器调用都会设置超时时间。

【热门文章】
【热门文章】