下面一段文字从别处引用:
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();
}
}
}