通常会有一些异步方法需要顺序执行,如对一个Socket进行异步发送,想要确保信息按照调用异步时的顺序进行发送,但使用普通的异步方法不能保证发送顺序,会导致对方接受结果为乱序发送。
具体实现思路:首先为每一个顺序声明一个ValueTask或Task全局变量a,然后每次调用异步方法时等待a中存储的前一个ValueTask或Task,同时将此次异步方法返回给a,这样就能实现异步的顺序发送。具体代码如下:
接收端代码:
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Bind(IPEndPoint.Parse("127.0.0.1:8888"));
byte[] buffer = new byte[10240];
socket.Listen(1);
Socket client = socket.Accept();
Thread.Sleep(5000);
client.Receive(buffer);
Console.WriteLine(Encoding.UTF8.GetString(buffer));
}
发送端代码(不进行异步顺序处理):
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect(IPEndPoint.Parse("127.0.0.1:8888"));
{
for (int i = 0; i < 100; i++)
{
Send_(socket, Encoding.UTF8.GetBytes($"{i}\n"));
}
}
}
static async void Send_(Socket socket,ReadOnlyMemory<byte>msgMem)
{
await Task.Delay(random.Next(10, 50)); //模拟多个方法处理时间不同操作
socket.SendAsync(msgMem);
}
普通异步方法输出:
发送端代码(顺序异步):
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect(IPEndPoint.Parse("127.0.0.1:8888"));
{
for (int i = 0; i < 100; i++)
{
globalVT = SendNext(socket, Encoding.UTF8.GetBytes($"{i}\n"));
}
}
}
static ValueTask<int> globalVT = default;
static async ValueTask<int> SendNext(Socket socket, ReadOnlyMemory<byte> msgMem)
{
//在一个代码块中,阻塞等待和赋值给globalVT二者不能同时发生,曲线救国
await globalVT;
return await send(socket, msgMem);
}
static async ValueTask<int> send(Socket socket, ReadOnlyMemory<byte> msgMem)
{
//异步方法,模拟延时操作
await Task.Delay(random.Next(10, 50));
return await socket.SendAsync(msgMem);
}