C#读写socket的常用方式
假设消息头为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 }