.net 3.5平台上的Socket开发

本文探讨了从.NET 2.0到3.5版本中Socket编程的改进,特别是通过使用SocketAsyncEventArgs替代IAsyncResult来减少垃圾回收负担,提高性能。文中详细介绍了如何实现高效的客户端连接管理和数据收发。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 其实这篇文章在一年前就应该写了,不过一直觉得自己没空,一拖就拖到现在。先对大家说句对不起了。

 

在之前的文章中,我们讲了如何在.NET 2.0下面开发Socket项目。其中的异步Socket让我们得以很轻松的在.NET中开发高性能服务端应用。

但是,在实际应用中我们还是发现了一些问题的存在,如:我们在每一次操作的过程中都要创建一个IAsyncResult上下文对象,如果数据通讯很频繁的话,会导致大量的IAsyncResult对象被创建,大大的增加了垃圾回收器的工作量,从而降低了整个应用的效率。

.NET 3.5中,这个麻烦已经被解决了,在3.5 版本中,Socket定义了一些新的方法。这些方法不要求每一次操作都创建一个新的上下文对象。 

如,在2.0中我们采用下面的方式在Socket上启动一次接收操作。

ContractedBlock.gif ExpandedBlockStart.gif Code
void ReceiveCallBack(IAsyncResult ar){}
IAsyncResult result
=socket.BeginReceive(info.Buffer, 0, info.Buffer.Length, SocketFlags.None, ReceiveCallBack, info);//在这里有一个IAsyncResult对象被创建。

3.5中我们可以用新的方法完成一次接收操作。

ContractedBlock.gif ExpandedBlockStart.gif 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 对象的属性提供。最后,需要使用事件处理程序回调完成方法。

让我们来看看代码:

首先我们创建一个用户类,用来存储和客户端有关的数据:

ContractedBlock.gif ExpandedBlockStart.gif Code
public class UserObject
ExpandedBlockStart.gifContractedBlock.gif    
{
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 接收数据的缓冲区
        
/// </summary>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public byte[] ReceiveBuffer getprivate set; }
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 发送数据的缓冲区
        
/// </summary>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public byte[] SendBuffer getprivate set; }
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 客户端Socket对象
        
/// </summary>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public Socket Socket getprivate set; }
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 发送数据上下文对象
        
/// </summary>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public SocketAsyncEventArgs SendEventArgs getprivate set; }
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 接收数据上下文对象
        
/// </summary>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public SocketAsyncEventArgs ReceiveEventArgs getprivate set; }

        
public UserObject(Socket socket)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            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);//设置发送缓冲区
        }

}
接下来我们开始接入客户端连接:
ContractedBlock.gif ExpandedBlockStart.gif 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)
12ExpandedBlockStart.gifContractedBlock.gif{
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}

好了,我们开始接收数据:

ContractedBlock.gif ExpandedBlockStart.gif Code
 1//接收数据完成事件处理程序
 2void Receives_Completed(object sender, SocketAsyncEventArgs e)
 3ExpandedBlockStart.gifContractedBlock.gif{
 4    var client = e.UserToken as UserObject;
 5    if (e.BytesTransferred == 0)//如果传输的数据量为0,则表示链接已经断开
 6ExpandedSubBlockStart.gifContractedSubBlock.gif     {
 7        Console.WriteLine("Socket:{0} is closed",client.Socket.Handle);
 8        client.Socket.Close();
 9    }

10    else
11ExpandedSubBlockStart.gifContractedSubBlock.gif    {
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)
24ExpandedBlockStart.gifContractedBlock.gif{
25    var client = e.UserToken as UserObject;
26    if (e.BytesTransferred==0)//如果传输的数据量为0,则表示链接已经断开
27ExpandedSubBlockStart.gifContractedSubBlock.gif    {
28        Console.WriteLine("Socket:{0} is closed", client.Socket.Handle);
29        client.Socket.Close();
30    }

31    else
32ExpandedSubBlockStart.gifContractedSubBlock.gif    {
33        Console.WriteLine("Sent {0} bytes data to socket:{1}",e.BytesTransferred, client.Socket.Handle);
34    }

35}
示例代码在: http://files.cnblogs.com/wzd24/ConsoleApplication2.rar

转载于:https://www.cnblogs.com/wzd24/archive/2009/03/09/1407248.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值