如何使用异步调用

下面一段文字从别处引用:

BeginInvoke方法用于启动异步调用。它与需要异步执行的方法具有相同的参数。此外,它还有两个可选参数。第一个参数是一个AsyncCallback委托,该委托引用在异步调用完成时要调用的方法。第二个参数是一个用户定义的对象,该对象可向回调方法传递数据。BeginInvoke立即返回,不会等待异步调用完成,被调用的方法将在线程池线程中执行。因此,提交请求的原始线程与执行异步方法的线程池线程是并行执行的。BeginInvoke会返回一个IAsyncResult对象,可以使用该对象来监视异步调用进度,也可将该对象传递给EndInvoke方法,以获取异步执行的方法的返回值。

EndInvoke方法用于检索异步调用的结果。调用BeginInvoke方法后可随时调用EndInvoke方法;如果异步调用尚未完成,EndInvoke方法将一直阻塞调用线程,直到异步调用完成后才允许调用线程执行。EndInvoke方法的参数包括需要异步执行的方法的out和ref参数,以及由BeginInvoke返回的IAsyncResult对象。因此,通过EndInvoke方法可以获得异步调用的方法的所有输出数据,包括返回值、out和ref参数。

AsyncCallback委托表示在异步操作完成时调用的回调方法,其定义如下:

public delegate void AsyncCallback(IAsyncResult ar);

一、下面是一个简单的例子:

public class Test
    {
        private int WorkerFunction(string a, string b)
        {
            //this is the guy that is supposed to do the long running work 
            Console.WriteLine(a);
            Console.WriteLine(b);
            return a.Length + b.Length;
        }

        private void MyCallBack(IAsyncResult ar)
        {
            var function = ar.AsyncState as Func<string, string, int>;
            int result = function.EndInvoke(ar);

            Thread.Sleep(1000);
            Console.WriteLine("Result is {0}", result);
        }
        public void CallMethod()
        {
            var function = new Func<string, string, int>(WorkerFunction);
            IAsyncResult result = function.BeginInvoke("param1", "param2", MyCallBack, function);
            //function.BeginInvoke("param1", "param2", MyCallBack, function);
            Console.WriteLine(" Finished begin invode.");
        }
    }
CallMethod()方法中首先定义了一个委托function,再用委托实现异步调用:
IAsyncResult result = function.BeginInvoke("param1", "param2", MyCallBack, function);
BeginInvoke方法有四个参数:
1.前两个是传递给被委托的方法WorkerFunciton(string p1, string p2)
2. 第三个参数MyCallBack是一个回调函数,在异步委托方法执行完成之后,会调用该回调方法。
  public delegate void MyCallBack(IAsyncResult ar);

IAsyncResult接口定义了四个公开属性,通过它们可以获取异步调用的状态。

—  AsyncState:获取用户定义的对象,它限定或包含关于异步操作的信息。

—  AsyncWaitHandle:获取用于等待异步操作完成的 WaitHandle。

—  CompletedSynchronously:获取异步操作是否同步完成的指示。

—  IsCompleted:获取异步操作是否已完成的指示。

3. 第四个参数function 是用于传递数据给回调函数。传递给MyCallBack的对象function存储在参数ar.AsyncState中。在callBack 函数中使用这个传回的对象前需要先将其转换为function的类型。
    var function = ar.AsyncState as Func<string, string, int>;
最后再回调函数中使用EndInvoke(ar)方法结束异步线程的使用。
当只需要实现异步调用,而不关心异步调用状态(什么时候结束)时,可以不用给出回调函数,直接用null替代即可,如下:
function.BeginInvoke("param1", "param2", Null, Null);

二、在socket client 程序中,经常需要连接server端,下面是一个异步连接server的实例,包括server端的连接,数据发送:
public class Client
    {
        private readonly string _hostname;
        private readonly int _port;
        private TcpClient _client;
        private NetworkStream _networkStream;

        private const int BufferSize = 4096;
        private readonly byte[] _buffer = new byte[BufferSize];

        public delegate void OnConnectedDelegate();
        public delegate void OnDataSentDelegate(string msg);
        public delegate void OnDataRecvDelegate(string msg);
        public delegate void OnClosedDelegate();

        public OnConnectedDelegate OnConnected;
        public OnClosedDelegate OnClosed;
        public OnDataSentDelegate OnDataSent;
        public OnDataRecvDelegate OnDataRecv;

        public Client(string hostname, int port)
        {
            if (string.IsNullOrEmpty(hostname) || port <= 0)
                throw new ArgumentException("Invalid IPAddress.");

            _hostname = hostname;
            _port = port;
        }

        public void Connect()
        {
            if (_client == null)
            {
                try
                {
                    _client = new TcpClient();

                    _client.BeginConnect(_hostname, _port, OnConnectedCallback, null);
                }
                catch (Exception ex)
                {
                    Logger.ErrorWithFormat("Failed to connect to {0}:{1}. {2}", _hostname, _port, ex.Message);

                    Close();
                }
            }
        }

        private void OnConnectedCallback(IAsyncResult ar)
        {
            try
            {
                _client.EndConnect(ar);

                _networkStream = _client.GetStream();

                if (OnConnected != null)
                    OnConnected();
            }
            catch (Exception ex)
            {
                Logger.ErrorWithFormat("Failed to connect to {0}:{1}. {2}", _hostname, _port, ex.Message);

                Close();
            }
        }

        public void Send(string msg)
        {
            if (string.IsNullOrEmpty(msg))
                return;

            byte[] bytes = Encoding.UTF8.GetBytes(msg);
            Send(bytes);
        }

        public void Send(byte[] bytes)
        {
            if (null == bytes)
                return;

            if (_networkStream != null)
            {
                try
                {
                    var msg = Encoding.UTF8.GetString(bytes);
                    _networkStream.BeginWrite(bytes, 0, bytes.Length, SendCallback, msg);
                }
                catch (Exception ex)
                {
                    Logger.ErrorWithFormat("Failed to send {0} bytes. {1}", bytes.Length, ex.Message);

                    Close();
                }
            }
        }

        private void SendCallback(IAsyncResult ar)
        {
            if (_networkStream != null)
            {
                try
                {
                    _networkStream.EndWrite(ar);

                    var msg = ar.AsyncState as string;
                    Logger.InfoWithFormat(" >> Sent msg : {0}", msg);

                    if (OnDataSent != null)
                    {
                        OnDataSent(msg);
                    }
                }
                catch (Exception ex)
                {
                    Logger.ErrorWithFormat("Failed to sent to {0}:{1}. {2}", _hostname, _port, ex.Message);

                    Close();
                }
            }
        }

        public void Read()
        {
            if (_networkStream != null)
            {
                try
                {
                    _networkStream.BeginRead(_buffer, 0, _buffer.Length, ReadCallback, null);
                }
                catch (Exception ex)
                {
                    Logger.ErrorWithFormat("Failed to read message. {0}", ex.Message);

                    Close();
                }
            }
        }

        private void ReadCallback(IAsyncResult ar)
        {
            if (_networkStream != null)
            {
                try
                {  
                    var bytesRead = _networkStream.EndRead(ar);
                    if (bytesRead > 0)
                    {
                        var msg = Encoding.UTF8.GetString(_buffer, 0, bytesRead);

                        Logger.InfoWithFormat(" >> Read msg : {0}", msg);

                        if (OnDataRecv != null)
                        {
                            OnDataRecv(msg);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Logger.ErrorWithFormat("Failed to read to {0}:{1}. {2}", _hostname, _port, ex.Message);

                    Close();
                }
            }
        }

        public void Close()
        {
            if (_networkStream != null)
            {
                _networkStream.Close();
                _networkStream = null;
            }

            if (_client != null)
            {
                _client.Close();
                _client = null;
            }

            if (OnClosed != null)
            {
                OnClosed();
            }
        }
    }

  

 
 
 

 

 

 

posted @ 2013-05-23 16:49  月光-日光海岸  阅读(273)  评论(0编辑  收藏  举报