Socket网络应用程序如同一般文件I/O一样在数据存取未完成的时候,整个应用程序会停滞,直到网络操作完全成功为止。若是遇上不佳的网络环境,这种情形将会严重影响整个网络程序的运作。对于网络延迟,.NET提供了自己的一组解决方法,异步操作。
Socket类提供的方法成员中包含一组专门用来进行异步操作的Socket方法。这些方法以成对出现:BeginConnect 与 EndConnect 提供异步联机功能、BeginAccept 与 EndAccept 提供异步接受请求、 BeginReceive与 EndReceive 异步接收数据、BeginSend与EndSend 异步发送数据。
其实这些方法和同步相当类似,最大的差异在于AsyncCallback类派生对象,上述的异步方法接受一个AsyncCallback对象,封装回调方法,并在Socket网络操作完成之后,返回IAsyncResult接口对象。此对象被当作参数。传入回调的方法,回调的方法调用结束相关异步方法,并且传入IAsyncResult,取得相关的异步操作信息。
public interface IAsyncResult
public delegate void AsyncCallback (IAsyncResult ar)
ar 为异步操作的结果,获取异步操作的返回值。
服务端代码示例
public static void StartListening(Socket listener, IPEndPoint localEndPoint)
{
listener.Bind(localEndPoint);
listener.Listen(100);
while (true)
{
//开启一个异步Socket来监听客户端连接请求,并建立回调方法AcceptCallback
AsyncCallback cb = new AsyncCallback(AcceptCallback);
IAsyncResult ar = listener.BeginAccept(cb, listener);
ShowMessage("正在等待一个新连接接入...");
ar.AsyncWaitHandle.WaitOne(); //等待连接
}
}
//请求回调过程(当有一个新客户端请求连接时发生)
private static void AcceptCallback(IAsyncResult ar)
{
//从IAsyncResult接口中得到客户端请求的Socket对象
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
//StateObject:一个用户定义对象,其中包含接收操作的相关信息。当操作完成时,
//此对象会被传递给EndReceive 委托。
StateObject state = new StateObject();
state.workSocket = handler;
//建立一个接收信息的回调,以便在收到信息时激发ReceiveCallback()过程
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state);
}
//接收信息回调过程(当接收到客户端信息时发生)
private static void ReceiveCallback(IAsyncResult ar)
{
String content = String.Empty;
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.workSocket;
//从客户端的Socket中读取信息
int bytesRead = handler.EndReceive(ar);
//在此加入信息处理并显示接收到的信息
//建立一个新的接收信息的回调,以便在收到新信息时继续本过程
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state);
}
辅助对象
public class StateObject
{
public Socket workSocket = null;
public const int BufferSize = 256;
public byte[] buffer = new byte[BufferSize];
public string strMsg = string.Empty;
}
客户端程序
private static ManualResetEvent connectDone = new ManualResetEvent(false);
private static ManualResetEvent sendDone = new ManualResetEvent(false);
private static ManualResetEvent receiveDone = new ManualResetEvent(false);
private static String response = String.Empty; //远程设备接收到的信息
public static void StartClient(Socket client, IPEndPoint remoteEP)
{
client.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), client);
connectDone.WaitOne();
}
private static void ConnectCallback(IAsyncResult ar)
{
Socket client = (Socket)ar.AsyncState;
client.EndConnect(ar);
System.Diagnostics.Debug.WriteLine("连接成功:" + client.RemoteEndPoint.ToString());
connectDone.Set();
}
private static void Receive(Socket client)
{
//创建stateObject.
StateObject state = new StateObject();
state.workSocket = client;
//开始从远程设备接收信息
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state);
}
private static void ReceiveCallback(IAsyncResult ar)
{
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket;
client = state.workSocket;
//读取信息
int bytesRead = client.EndReceive(ar);
//信息处理
}
public static void Send(Socket client, String data)
{
byte[] byteData = Encoding.UTF8.GetBytes(data);
//向远程设备发送信息
client.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), client);
}
private static void SendCallback(IAsyncResult ar)
{
Socket client = (Socket)ar.AsyncState;
//所有信息已被发送
int bytesSent = client.EndSend(ar);
}
上面的示例只说明了异步聊天程序的原理,没有对可能发生的异常进行处理和其它辅助方法。
http://blog.youkuaiyun.com/chendazhi/archive/2006/04/21/socket