zoukankan      html  css  js  c++  java
  • [C#]Socket通信BeginReceive异步接收数据何时回调Callback

    原文地址: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 方法。

  • 相关阅读:
    大话设计模式笔记(二十)の命令模式
    大话设计模式笔记(十九)の桥接模式
    大话设计模式笔记(十八)の单例模式
    大话设计模式笔记(十七)の迭代器模式
    反射的使用及其使用场景
    linq的简单使用
    XML的简单使用
    log4net的简单使用
    token
    axios在vue中的简单封装及应用
  • 原文地址:https://www.cnblogs.com/wangtonghui/p/3277303.html
Copyright © 2011-2022 走看看