惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

J
Java Code Geeks
量子位
腾讯CDC
A
About on SuperTechFans
小众软件
小众软件
Microsoft Azure Blog
Microsoft Azure Blog
T
Tailwind CSS Blog
V
V2EX
B
Blog RSS Feed
H
Hackread – Cybersecurity News, Data Breaches, AI and More
GbyAI
GbyAI
Recent Announcements
Recent Announcements
Microsoft Security Blog
Microsoft Security Blog
博客园 - 叶小钗
罗磊的独立博客
宝玉的分享
宝玉的分享
WordPress大学
WordPress大学
大猫的无限游戏
大猫的无限游戏
IT之家
IT之家
V
Visual Studio Blog
D
DataBreaches.Net
博客园 - 三生石上(FineUI控件)
月光博客
月光博客
有赞技术团队
有赞技术团队

博客园 - ahui

解决在IIS中调用Microsoft Office Excel组件后进程无法正常退出的问题 Javascript实现scroll时固定html元素 [小技巧]提交数据并下载文件的实现方式 轻量级DbHelper同时支持多个不同的数据库 Emit实现简单的C# AOP框架 Reflector的替代方案 .NET2.0项目Ajax请求处理 EntityFramework4.1和ADO.NET插入操作性能比较 一道算法题(负数左边,正数右边)的最优答案 MVC+ExtJs之验证信息无缝结合 16进制字符串和Byte之间的互转 设置预览图片自适应(保持原比例) Entity Framework4.1实现动态多条件查询、分页和排序 异步接收Socket数据 Mysql备份代码 android下修改hosts文件 Android和.NET通用的AES算法 .NET和Android解压缩处理 Android轻量级JSON操作类
C#读写socket的常用方式
ahui · 2011-07-12 · via 博客园 - ahui

假设消息头为16byte

0-3   消息头标识

4-7   消息体长度

8-15 CRC校验码

public class StreamHelper
    {
        #region 将消息转为包含消息头的字节数组
        /// <summary>
        /// 将消息转为包含消息头的字节数组
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="message"></param>
        /// <returns></returns>
        public static byte[] GetWrappedMessage(Google.ProtocolBuffers.IMessage message)
        {
            byte[] buff = message.ToByteArray();
            CRC32 crc32 = new CRC32();
            crc32.Update(buff);

            MemoryStream ms = new MemoryStream();
            byte[] tag = BitConverter.GetBytes(Constants.Tag);
            byte[] len = BitConverter.GetBytes(buff.Length);
            byte[] crc = BitConverter.GetBytes(crc32.Value);

            ms.Write(tag, 0, tag.Length); // 写入标头
            ms.Write(len, 0, len.Length); // 写入消息长度
            ms.Write(crc, 0, crc.Length); // 写入crc32值
            ms.Write(buff, 0, buff.Length);

            byte[] result = ms.ToArray();
            ms.Close();

            return result;
        }
        #endregion

        #region 将消息写入流
        /// <summary>
        /// 将消息写入流
        /// </summary>
        /// <param name="stream"></param>
        /// <returns></returns>
        public static void WriteToStream(NetworkStream stream, Google.ProtocolBuffers.IMessage message)
        {
            byte[] buff = message.ToByteArray();
            CRC32 crc32 = new CRC32();
            crc32.Update(buff);

            byte[] tag = BitConverter.GetBytes(Constants.Tag);
            byte[] len = BitConverter.GetBytes(buff.Length);
            byte[] crc = BitConverter.GetBytes(crc32.Value);

            stream.Write(tag, 0, tag.Length); // 写入标头
            stream.Write(len, 0, len.Length); // 写入消息长度
            stream.Write(crc, 0, crc.Length); // 写入crc32值
            stream.Write(buff, 0, buff.Length);
        }
        #endregion

        #region 将消息写入Socket
        /// <summary>
        /// 将消息写入Socket
        /// </summary>
        /// <param name="socket"></param>
        /// <returns></returns>
        public static void WriteToSocket(Socket socket, Google.ProtocolBuffers.IMessage message)
        {
            byte[] buff = message.ToByteArray();
            CRC32 crc32 = new CRC32();
            crc32.Update(buff);

            byte[] tag = BitConverter.GetBytes(Constants.Tag);
            byte[] len = BitConverter.GetBytes(buff.Length);
            byte[] crc = BitConverter.GetBytes(crc32.Value);

            socket.SendBufferSize = Constants.HeadSize + buff.Length;

            socket.Send(tag); // 写入标头
            socket.Send(len); // 写入消息长度
            socket.Send(crc); // 写入crc32值
            socket.Send(buff);
        }
        #endregion

        #region 从NetworkStream读出所有字节
        /// <summary>
        /// 从NetworkStream读出所有字节
        /// </summary>
        /// <param name="stream"></param>
        /// <returns></returns>
        public static byte[] ReadAllBytes(NetworkStream stream)
        {
            byte[] head = new byte[Constants.HeadSize];
            if (stream.Read(head, 0, Constants.HeadSize) != Constants.HeadSize) // 传输头16位,仅校验数据使用
            {
                return null;
            }

            HeadInfo headInfo = new HeadInfo(head);
            if (headInfo.Tag != Constants.Tag) // 标头不正确
            {
                return null;
            }

            byte[] buff = new byte[headInfo.Len];
            int size = Math.Min(buff.Length, 4096); // 一次最多读取多少个字节
            int offset = 0;
            do
            {
                size = Math.Min(size, headInfo.Len - offset);
                offset += stream.Read(buff, offset, size);
                if (offset == headInfo.Len) // 接收到指定的长度
                {
                    CRC32 crc32 = new CRC32();
                    crc32.Update(buff);
                    if (crc32.Value == headInfo.Crc32Value) // 验证CRC32
                    {
                        return buff;
                    }
                }
            }
            while (stream.DataAvailable);

            Log.ErrorFormat("客户端请求失败: offset {0}, head len {1}", offset, headInfo.Len);

            return null;
        }
        #endregion

        #region 从Socket读出所有字节
        /// <summary>
        /// 从Socket读出所有字节
        /// </summary>
        /// <param name="socket"></param>
        /// <returns></returns>
        public static byte[] ReadAllBytes(Socket socket)
        {
            byte[] head = new byte[Constants.HeadSize];
            byte[] result = null;

            SocketError error = SocketError.Success;
            int maxRepeat = 5;
            int got = 0;
            int repeat = 0;

            do // 读取标头
            {
                got += socket.Receive(head, got, Constants.HeadSize - got, SocketFlags.None, out error);
                if (got == Constants.HeadSize || repeat > maxRepeat) // 接收完全或者重复10次仍然没接收
                {
                    break;
                }
                else if (got == 0) // 获取不到数据重复的次数
                {
                    ++repeat;
                }
            }
            while (error == SocketError.Success);

            if (got != Constants.HeadSize) // 验证标头长度
            {
                Log.Error("Head长度不正确");
                return null;
            }

            HeadInfo headInfo = new HeadInfo(head);
            if (headInfo.Tag != Constants.Tag) // 标头不正确
            {
                Log.ErrorFormat("Head.Tag不正确(应为{0}, 实际{1})", Constants.Tag, headInfo.Tag);
                return null;
            }

            result = new byte[headInfo.Len];
            repeat = 0;
            got = 0;
            do // 读取消息体
            {
                got += socket.Receive(result, got, result.Length - got, SocketFlags.None, out error);
                if (got == result.Length || repeat > maxRepeat) // 接收完全或者重复10次仍然没接收
                {
                    break;
                }
                else if (got == 0) // 获取不到数据重复的次数
                {
                    ++repeat;
                }
            }
            while (error == SocketError.Success);

            if (got != result.Length) // 验证长度
            {
                Log.ErrorFormat("长度不正确(应为{0}, 实际{1})", result.Length, got);
                return null;
            }

            CRC32 crc32 = new CRC32();
            crc32.Update(result);
            if (crc32.Value != headInfo.Crc32Value) // 验证CRC32
            {
                Log.ErrorFormat("CRC校验失败(应为{0}, 实际{1})", headInfo.Crc32Value, crc32.Value);
                return null;
            }

            return result;
        }
        #endregion

        #region 异步接收Socket数据(测试用)
        /// <summary>
        /// 异步接收Socket数据
        /// </summary>
        /// <param name="socket"></param>
        /// <returns></returns>
        public static byte[] ReceiveData(Socket socket)
        {
            ReceiveObject state = new ReceiveObject() { Client = socket };
            socket.BeginReceive(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, new AsyncCallback(ReadCallback), state);
            state.ReceiveDone.WaitOne(socket.ReceiveTimeout); // 超时设置

            byte[] head = new byte[Constants.HeadSize];
            state.Stream.Seek(0, SeekOrigin.Begin);
            if (state.Stream.Read(head, 0, Constants.HeadSize) != Constants.HeadSize) // 读取标头
            {
                return null;
            }

            HeadInfo headInfo = new HeadInfo(head);
            if (headInfo.Tag != Constants.Tag) // 标头不正确
            {
                return null;
            }
            if (state.Stream.Length - 16 != headInfo.Len) // 验证长度
            {
                return null;
            }

            // state.Stream.Seek(16, SeekOrigin.Begin);
            byte[] result = new byte[state.Stream.Length - 16];
            state.Stream.Read(result, 0, result.Length); // 读取消息体

            CRC32 crc32 = new CRC32();
            crc32.Update(result);
            if (crc32.Value == headInfo.Crc32Value) // 验证CRC32
            {
                return result;
            }

            return null;
        }

        /// <summary>
        /// 同步接收对象
        /// </summary>
        private class ReceiveObject : IDisposable
        {
            public Socket Client;
            public byte[] Buffer = new byte[4096];
            public System.IO.MemoryStream Stream = new System.IO.MemoryStream();
            public System.Threading.ManualResetEvent ReceiveDone = new System.Threading.ManualResetEvent(false);

            public void Dispose()
            {
                this.Stream.Close();
            }
        }

        /// <summary>
        /// read回调
        /// </summary>
        /// <param name="ar"></param>
        private static void ReadCallback(IAsyncResult ar)
        {
            ReceiveObject state = (ReceiveObject)ar.AsyncState;
            int bytesRead = state.Client.EndReceive(ar);
            if (bytesRead > 0)
            {
                try
                {
                    state.Stream.Write(state.Buffer, 0, bytesRead);
                    state.Client.BeginReceive(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, new AsyncCallback(ReadCallback), state);
                }
                catch (Exception ex)
                {
                    Log.Error(ex.Message);
                    state.ReceiveDone.Set();
                }
            }
            else
            {
                state.ReceiveDone.Set();
                // state.Client.EndReceive(ar);
            }
        }
        #endregion
    }