/// <summary> /// 异步接收操作完成时调用此方法 /// 如果远程主机关闭了连接,则该套接字被关闭 /// 如果接收到数据,则数据将回传给客户端 /// </summary> /// <param name="e"></param> private void ProcessReceive(SocketAsyncEventArgs e) { try { // 检查如果客户端关闭连接 AsyncUserToken token = (AsyncUserToken)e.UserToken; // 获取用户信息 if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success) // 如果字节存在 { Byte[] data = new Byte[e.BytesTransferred]; // 从套接字中获取数据 Array.Copy(e.Buffer, e.Offset, data, 0, e.BytesTransferred); lock (token.Buffer) { token.Buffer.AddRange(data);// 锁定接收数据 } //注意:你一定会问,这里为什么要用do-while循环? //如果当客户发送大数据流的时候,e.BytesTransferred的大小就会比客户端发送过来的要小, //需要分多次接收.所以收到包的时候,先判断包头的大小.够一个完整的包再处理. //如果客户短时间内发送多个小数据包时, 服务器可能会一次性把他们全收了. //这样如果没有一个循环来控制,那么只会处理第一个包, //剩下的包全部留在token.Buffer中了,只有等下一个数据包过来后,才会放出一个来. do { byte[] lenBytes = token.Buffer.GetRange(0, 4).ToArray(); // 获取头说明 int packageLen = BitConverter.ToInt32(lenBytes, 0); // 获取包长度 if (packageLen > token.Buffer.Count - 4) { break; // 长度不够时,退出循环,让程序继续接收 } byte[] rev = token.Buffer.GetRange(4, packageLen).ToArray(); // 包够长时,则提取出来,交给后面的程序去处理 lock (token.Buffer) { token.Buffer.RemoveRange(0, packageLen + 4); // 锁定线程并从数据池中移除这组数据 } ReceiveClientData?.Invoke(token, rev); // 将数据包交给后台处理,这里你也可以新开个线程来处理.加快速度 //string msg = Encoding.UTF8.GetString(rev); //server.lbxInfo.Items.Add(msg);// 输出信息 //这里API处理完后,并没有返回结果,当然结果是要返回的,却不是在这里, 这里的代码只管接收. //若要返回结果,可在API处理中调用此类对象的SendMessage方法,统一打包发送.不要被微软的示例给迷惑了. } while (token.Buffer.Count > 4); //继续接收. 为什么要这么写,请看Socket.ReceiveAsync方法的说明 if (!token.Socket.ReceiveAsync(e)) { this.ProcessReceive(e); } } else { CloseClientSocket(e); } } catch (Exception ex) { AsyncUserToken token = e.UserToken as AsyncUserToken; log.AddLog(LogType.Error, $"异步接收数据操作时出错!\r\n客户端地址:{token.IPAddress}\r\n错误信息:{ex.Message}"); } }
private void ProcessReceive(SocketAsyncEventArgs e) { try { // check if the remote host closed the connection UserToken token = (UserToken)e.UserToken; if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success) { //读取数据 byte[] data = new byte[e.BytesTransferred]; Array.Copy(e.Buffer, e.Offset, data, 0, e.BytesTransferred); lock (token.Buffer) { token.Buffer.AddRange(data); } do { //判断包的长度 byte[] lenBytes = token.Buffer.GetRange(0, 4).ToArray(); int packageLen = BitConverter.ToInt32(lenBytes, 0); if (packageLen > token.Buffer.Count - 4) { //长度不够时,退出循环,让程序继续接收 break; } //包够长时,则提取出来,交给后面的程序去处理 byte[] rev = token.Buffer.GetRange(4, packageLen).ToArray(); //从数据池中移除这组数据 lock (token.Buffer) { token.Buffer.RemoveRange(0, packageLen + 4); } ReceiveClientData?.Invoke(token, rev); } while (token.Buffer.Count > 4); if (!token.Socket.ReceiveAsync(e)) { this.ProcessReceive(e); } } else { //CloseClientSocket(e); } } catch (Exception xe) { Console.WriteLine(xe.Message + "\r\n" + xe.StackTrace); } }