因为没有文件上传,没有大的字节传输,数据过来就放到队列,所以没有用异步,采用的是同步的方式来处理。
原理就是:
1.前面四个字节定义消息长度;
2.后面字节定义消息体;
3.服务端收到消息后,根据长度来获取消息体,有多余的继续当做头部获取
private void Receive(Socket socket, string ip) { Task.Factory.StartNew(() => { var pack = new BytePkg(); while (true) { try { //如果socket已经断开,结束循环 if (!socket.Connected) { _logger.Warn($"IP:{ip},socket已断开,停止接收数据;"); break; } byte[] prevBytes = new byte[1024]; int len = socket.Receive(prevBytes, prevBytes.Length, SocketFlags.None); var bytes = prevBytes.Take(len).ToArray(); this.RcvHeadData(pack, bytes); } catch (Exception ex) { _logger.Error($"IP:{ip},接收socket数据异常,message:{ex.Message},stackTrace:{ex.StackTrace};"); } } }); } /// <summary> /// 消息头 /// </summary> /// <param name="pack"></param> /// <param name="bytes"></param> private void RcvHeadData(BytePkg pack, byte[] bytes) { var len = bytes.Length; pack.headIndex += len;if (pack.headIndex < pack.headLen) {for (int x = 0; x < len; x++) { pack.headBuff[pack.headIndex - len + x] = bytes[x]; }; } else {var actualHeadLen = pack.headIndex - len;//head的实际长度 var skipHeadLen = pack.headLen - actualHeadLen;//需要补上的长度;head定义长度 - head的实际长度 = body需要跳过的长度 for (int x = 0; x < skipHeadLen; x++) { pack.headBuff[actualHeadLen + x] = bytes[x]; }//★★★★★开始处理消息体部分★★★★★ var bodyLen = len;//身体长度 if (skipHeadLen > 0) { bodyLen = len - skipHeadLen;//第一次,获取剩余部分的长度 pack.InitBodyBuff();//第一次,需要初始化body }this.RcvBodyData(pack, bytes.Skip(skipHeadLen).Take(bodyLen).ToArray()); } } /// <summary> /// 消息体 /// </summary> /// <param name="pack"></param> /// <param name="bytes"></param> private void RcvBodyData(BytePkg pack, byte[] bytes) { var len = bytes.Length; pack.bodyIndex += len; if (pack.bodyIndex < pack.bodyLen) {for (int x = 0; x < len; x++) { pack.bodyBuff[pack.bodyIndex - len + x] = bytes[x]; }; } else {var actualBodyLen = pack.bodyIndex - len;//body的实际长度 var skipBodyLen = pack.bodyLen - actualBodyLen;//需要补上的长度;body定义长度 - body的实际长度 = 本次需要获取的body长度 for (int x = 0; x < skipBodyLen; x++) { pack.bodyBuff[actualBodyLen + x] = bytes[x]; } //处理接收到的数据 NetMsg msg = ByteHelper.DeSerialize<NetMsg>(pack.bodyBuff); this.OnReceiveMsg(msg); //重置信息包 pack.ResetData();//★★★★★开始处理消息头部分★★★★★ this.RcvHeadData(pack, bytes.Skip(skipBodyLen).ToArray()); } }
如果不放心,可以在该加日志的地方加上日志。然后观察代码的逻辑是否正确。