但是,在實際應用中我們還是發現了一些問題的存在,如:我們在每一次操作的過程中都要創建一個IAsyncResult上下文對象,如果數據通訊很頻繁的話,會導致大量的IAsyncResult對象被創建,大大的增加了垃圾回收器的工作量,從而降低了整個應用的效率。
在.NET 3.5中,這個麻煩已經被解決了,在3.5 版本中,Socket定義了一些新的方法。這些方法不要求每一次操作都創建一個新的上下文對象。
如,在2.0中我們採用下面的方式在Socket上啓動一次接收操作。3.5中我們可以用新的方法完成一次接收操作。
Code
void ReceiveCallBack(IAsyncResult ar){}
IAsyncResult result=socket.BeginReceive(info.Buffer, 0, info.Buffer.Length, SocketFlags.None, ReceiveCallBack, info);//在這裏有一個IAsyncResult對象被創建。
在
Code
void OnReceiveCompleted(object sender,SocketAsyncEventArgs e){}
SocketAsyncEventArgs receive=new SocketAnyncEventArgs();
receive.Completed+= OnReceiveCompleted;
receive.SetBuffer(buffer,0,buffer.Length);
socket.ReceiveAsync(receive);
在這裏我們可以看出3.5 和 2.0 的一個明顯區別,那就是不是使用IAsyncResult而是用SocketAsyncEventArgs作爲上下文對象。應用程序創建並管理(並且可以重複使用)SocketAsyncEventArgs 對象。套接字操作的所有參數都由 SocketAsyncEventArgs 對象的屬性和方法指定。完成狀態也由 SocketAsyncEventArgs 對象的屬性提供。最後,需要使用事件處理程序回調完成方法。
讓我們來看看代碼:
首先我們創建一個用戶類,用來存儲和客戶端有關的數據:
Code
public class UserObject
{
/**//// <summary>
/// 接收數據的緩衝區
/// </summary>
public byte[] ReceiveBuffer { get; private set; }
/**//// <summary>
/// 發送數據的緩衝區
/// </summary>
public byte[] SendBuffer { get; private set; }
/**//// <summary>
/// 客戶端Socket對象
/// </summary>
public Socket Socket { get; private set; }
/**//// <summary>
/// 發送數據上下文對象
/// </summary>
public SocketAsyncEventArgs SendEventArgs { get; private set; }
/**//// <summary>
/// 接收數據上下文對象
/// </summary>
public SocketAsyncEventArgs ReceiveEventArgs { get; private set; }
public UserObject(Socket socket)
{
ReceiveBuffer = new byte[1024];//定義接收緩衝區
SendBuffer = new byte[1024];//定義發送緩衝區
this.Socket = socket;
SendEventArgs = new SocketAsyncEventArgs();
SendEventArgs.UserToken = this;
ReceiveEventArgs = new SocketAsyncEventArgs();
ReceiveEventArgs.UserToken = this;
ReceiveEventArgs.SetBuffer(ReceiveBuffer, 0, ReceiveBuffer.Length);//設置接收緩衝區
SendEventArgs.SetBuffer(SendBuffer, 0, SendBuffer.Length);//設置發送緩衝區
}
}
接下來我們開始接入客戶端連接:
Code
1socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
2socket.Bind(localEP);
3socket.Listen(100);
4Console.WriteLine("Server is bind on {0}",socket.LocalEndPoint);
5acceptEventArgs = new SocketAsyncEventArgs();//創建接入Socket上下文對象
6acceptEventArgs.Completed += acceptCompleted;//註冊接入完成事件處理程序
7socket.AcceptAsync(acceptEventArgs);//投遞接入操作
8Console.WriteLine("Server is started");
9
10//接入事件處理程序
11void acceptCompleted(object sender, SocketAsyncEventArgs e)
12{
13 var client = new UserObject( e.AcceptSocket);//創建用戶對象實例
14 client.ReceiveEventArgs.Completed += Receives_Completed;//註冊接收數據完成事件處理程序
15 client.SendEventArgs.Completed += Send_Completed;//註冊發送數據完成事件處理程序
16 client.Socket.ReceiveAsync(client.ReceiveEventArgs);//投遞接收數據操作
17}
好了,我們開始接收數據:
Code
1//接收數據完成事件處理程序
2void Receives_Completed(object sender, SocketAsyncEventArgs e)
3{
4 var client = e.UserToken as UserObject;
5 if (e.BytesTransferred == 0)//如果傳輸的數據量爲0,則表示鏈接已經斷開
6 {
7 Console.WriteLine("Socket:{0} is closed",client.Socket.Handle);
8 client.Socket.Close();
9 }
10 else
11 {
12 string message = Encoding.Unicode.GetString(e.Buffer, 0, e.BytesTransferred);//獲取接收到的數據
13 Console.WriteLine("Socket:{0} send message:{1}",client.Socket.Handle,message);
14 string sent=string.Format("{0} bytes has been received",e.BytesTransferred);
15 int length = Encoding.Unicode.GetBytes(sent,0,sent.Length,client.SendBuffer,0);//將數據寫入發送緩衝區
16 client.SendEventArgs.SetBuffer(0, length);//設置緩衝區中有效數據的偏移量和長度
17 client.Socket.SendAsync(client.SendEventArgs);//投遞發送數據操作
18 client.Socket.ReceiveAsync(client.ReceiveEventArgs);//投遞接收數據操作
19 }
20}
21
22//發送數據完成事件處理程序
23void Send_Completed(object sender, SocketAsyncEventArgs e)
24{
25 var client = e.UserToken as UserObject;
26 if (e.BytesTransferred==0)//如果傳輸的數據量爲0,則表示鏈接已經斷開
27 {
28 Console.WriteLine("Socket:{0} is closed", client.Socket.Handle);
29 client.Socket.Close();
30 }
31 else
32 {
33 Console.WriteLine("Sent {0} bytes data to socket:{1}",e.BytesTransferred, client.Socket.Handle);
34 }
35}
示例代碼在:http://files.cnblogs.com/wzd24/ConsoleApplication2.rar