原文地址:http://www.cnblogs.com/wangtonghui/p/3277303.html
最近在做服务器压力测试程序。
接触了一段时间Socket异步通讯,发现自己对BeginReceive什么时候回调产生了错误的理解。之前我一直以为异步接收数据只有当Buffer被填满的时候才会回调。如果这样当服务端的Buffer大于客户端发送的数据时,客户端发送的数据就不会得到及时的处理(当Buffer填满时才处理)。这显然是不合情理的,于是我做了如下测试:
服务端代码:
客户端代码:using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net; using System.Net.Sockets; namespace SocketServer { class Program { //服务端buffer为4字节 static byte[] buffer = new byte[4]; static void Main(string[] args) { Console.WriteLine("[Server]"); try { Socket socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); socketServer.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 4444)); socketServer.Listen(int.MaxValue); Console.WriteLine("服务端已启动,等待连接..."); //接收连接 Socket ts = socketServer.Accept(); Console.WriteLine("客户端已连接"); //开始异步接收 ts.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), ts); Console.ReadKey(); } catch (Exception e) { Console.WriteLine(e.Message); } } static void ReceiveCallback(IAsyncResult result) { Socket ts = (Socket)result.AsyncState; ts.EndReceive(result); result.AsyncWaitHandle.Close(); Console.WriteLine("收到消息:{0}", Encoding.ASCII.GetString(buffer)); //清空数据,重新开始异步接收 buffer = new byte[buffer.Length]; ts.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), ts); } } }using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net; using System.Net.Sockets; namespace SocketClient { class Program { static void Main(string[] args) { Console.WriteLine("[Client]"); try { Socket socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); socketClient.Connect(IPAddress.Parse("127.0.0.1"), 4444); Console.WriteLine("发送消息:"); //获取发送内容 string sendStr = Console.ReadLine(); while (!(sendStr.ToLower() == "q")) { Console.WriteLine("发送消息:"); //同步发送数据 socketClient.Send(Encoding.ASCII.GetBytes(sendStr)); sendStr = Console.ReadLine(); } } catch (Exception e) { Console.WriteLine(e.Message); Console.WriteLine("按任意键退出"); Console.ReadKey(); } } } }
可以看到服务端采用异步接收的方式,每次接收不超过4个字节。客户端不限制一次发送数据的字节数。(备注:1.先运行服务端后运行客户端 2.发送数据采用ASCII编码,每个字符占用1个字节 3.Socket.ReceiveBufferSize应当大于Buffer长度,否则会得到其他结果)
测试结果:
1.发送数据长度与接收Buffer长度一致,接收到所有数据回调;
2.发送数据长度大于接收Buffer长度,Buffer填满时回调,数据接收完时回调;
3.发送数据长度小于接收Buffer长度,数据接收完时回调;
如果想要手动强制使BeginReceive回调,MSDN提供的方法是:
若要取消挂起的 BeginReceive,请调用 Close 方法。