C#使用Pipelines实现处理Socket数据包

 更新时间:2023年12月27日 08:19:53   作者:rjcql  
这篇文章主要为大家详细介绍了C#如何使用Pipelines实现处理Socket数据包,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

写在前面

在上一篇中对Pipelines进行简单的了解,同时也留下了未解的问题,如何将Pipelines类库运用到Socket通讯过程中来解决粘包和分包。链接地址如下:C#中System.IO.Pipelines库的使用详解

这一篇做了一个完整的demo,使用Pipelines接收和处理来自多个客户端发出的消息;相对于以往在报文包头放包体长度再结合结束符来判断的方式,确实要简洁了许多。

代码实现

服务端实现

using System.Net.Sockets;
using System.Net;
using System.Text;
 
class Program
{
    static async Task Main()
    {
        SocketServerForPiplines();
    }
 
    static async void SocketServerForPiplines()
    {
        Console.WriteLine("Socket Server");
 
        // 创建服务端Socket对象
        var serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        serverSocket.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9090));
        serverSocket.ReceiveTimeout = 1000;
        serverSocket.SendTimeout = 1000;
        serverSocket.Listen(1000);
        Console.WriteLine("服务端启动监听");
 
        while (true)
        {
            var clientSocket = serverSocket.Accept();
 
            Console.WriteLine("有客户端连上了");
 
            var handler = new PiplinesHandler(clientSocket);
            await handler.StartReceiveAsync();
        }
 
        Console.ReadLine();
    }
}

PiplinesHandler类

using System;
using System.Buffers;
using System.Collections.Generic;
using System.IO.Pipelines;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
 
namespace PipelinesTester
{
    public class PiplinesHandler
    {
        private const int _minimumBufferSize = 512;
        private Socket _socket;
        private Pipe _pipe;
 
        public PiplinesHandler(Socket socket)
        {
            _socket = socket;
            var options = new PipeOptions(pauseWriterThreshold: 4096, resumeWriterThreshold: 1024);
            _pipe = new Pipe(options);
        }
 
        public async Task StartReceiveAsync()
        {
            Task receiveTask = ReceiveMessageAsync();
            Task processTask = ProcessMessageAsync();
 
            await Task.WhenAll(receiveTask, processTask);
        }
 
 
        private async Task ReceiveMessageAsync()
        {
            PipeWriter writer = _pipe.Writer;
 
            while (true)
            {
                try
                {
                    //从writer申请缓冲区
                    Memory<byte> memory = writer.GetMemory(_minimumBufferSize);
                    //从socket读取数据,直接写入到缓冲区中,即直接写入了PipeWriter中        
                    int bytesRead = await _socket.ReceiveAsync(memory, SocketFlags.None);
                    if (bytesRead == 0)
                    {
                        break;
                    }
                    //前移写标志位
                    writer.Advance(bytesRead);
                    //通知Reader,可以读取了
                    var result = await writer.FlushAsync();
 
                    if (result.IsCompleted)
                        break;
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                    break;
                }
 
            }
 
            await writer.CompleteAsync();
 
            try
            {
                _socket.Shutdown(SocketShutdown.Both);
                _socket.Close();
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
        }
 
        private async Task ProcessMessageAsync()
        {
            PipeReader _pipeReader = _pipe.Reader;
 
            while (true)
            {
                //读取消息
                var result = await _pipeReader.ReadAsync();
                var buffer = result.Buffer;
                //查找结束符            
                SequencePosition? position = buffer.PositionOf((byte)'\n');
 
                if (position == null)
                {
                    continue;
                }
 
                // 处理消息
                var line = buffer.Slice(0, position.Value);
                string msg = Encoding.UTF8.GetString(line);
                Console.WriteLine(msg);
 
                // 前移PipeReader
                buffer = buffer.Slice(buffer.GetPosition(1, position.Value));
                _pipeReader.AdvanceTo(buffer.Start, buffer.End);
 
                // Stop reading if there's no more data coming.
                if (result.IsCompleted)
                {
                    break;
                }
            }
 
            await _pipeReader.CompleteAsync();
        }
    }
}

客户端实现

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
 
class Program
{
    static void Main(string[] args)
    {
        TcpClientTest();
    }
 
    static void TcpClientTest()
    {
        Console.WriteLine("TcpClient");
 
        var msg = $"这是来自客户端的消息{DateTime.Now.ToString("yyyy-MM-dd:HH:mm:ss")}\n";
        var client = new TcpClient("127.0.0.1", 9090);
        var sendStream = client.GetStream();
        var sendBytes = Encoding.Default.GetBytes(msg);
        sendStream.Write(sendBytes, 0, sendBytes.Length);
        sendStream.Flush();
        sendStream.Close();//关闭网络流  
        client.Close();//关闭客户端  
 
        Console.WriteLine(msg);
 
        Console.ReadLine();
    }
}

调用示例

到此这篇关于C#使用Pipelines实现处理Socket数据包的文章就介绍到这了,更多相关C# Pipelines处理Socket内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C# 在PDF中创建和填充域

    C# 在PDF中创建和填充域

    本文主要介绍了C# 在PDF中创建和填充域的相关知识。具有很好的参考价值,下面跟着小编一起来看下吧
    2017-03-03
  • C#控制台程序使用Log4net日志组件详解

    C#控制台程序使用Log4net日志组件详解

    这篇文章主要为大家详细介绍了C#控制台程序使用Log4net日志组件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-05-05
  • c#程序删除自身代码示例分享

    c#程序删除自身代码示例分享

    偶然看到一个可以自删除的程序,于是了解下如何实现。然后整理如下,需要的朋友可以参考下
    2014-03-03
  • 详解C#实现MD5加密的示例代码

    详解C#实现MD5加密的示例代码

    本篇文章主要介绍了C#实现MD5加密的示例代码,详细的介绍了几种方法,具有一定的参考价值,有兴趣的可以了解一下。
    2016-12-12
  • C#设置Word文档背景的三种方法(纯色/渐变/图片背景)

    C#设置Word文档背景的三种方法(纯色/渐变/图片背景)

    本文给大家分享三种添加Word文档背景的方法,非常不错,代码简单易懂,具有参考借鉴价值,需要的朋友参考下吧
    2018-03-03
  • C# 微信支付回调验签处理的实现

    C# 微信支付回调验签处理的实现

    在微信支付中,当用户支付成功后,微信会把相关支付结果和用户信息发送给商户,本文就详细的介绍了C# 微信支付回调验签处理,具有一定的参考价值,感兴趣的可以了解一下
    2021-12-12
  • C# Console.WriteLine()用法案例详解

    C# Console.WriteLine()用法案例详解

    这篇文章主要介绍了C# Console.WriteLine()用法案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • 浅析C#中数组,ArrayList与List对象的区别

    浅析C#中数组,ArrayList与List对象的区别

    在C#中,当我们想要存储一组对象的时候,就会想到用数组,ArrayList,List这三个对象了。那么这三者到底有什么样的区别呢
    2013-07-07
  • C#中Mutex对象用法分析

    C#中Mutex对象用法分析

    这篇文章主要介绍了C#中Mutex对象用法,结合实例形式分析了Mutex对象的功能与线程操作的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2016-06-06
  • C#中async/await之线程上下文工作原理

    C#中async/await之线程上下文工作原理

    这篇文章主要为大家介绍了C#中async/await之线程上下文工作原理解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪<BR>
    2023-05-05

最新评论