// Should validate the handshake response from the server private void ReceiveAsync_Completed(object sender, SocketAsyncEventArgs e) { if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success) { int bytesAlreadyProcessed = 0; // Count of the total freshly transferred bytes processed so far ReceiveToken token = (ReceiveToken)e.UserToken; if (!headerExchanged) { byte[] header = HandleHttpHeader(e, ref bytesAlreadyProcessed); token = (ReceiveToken)e.UserToken; if (header == null) { DoRead(e); return; } else if (Websockets.ValidateResponseHeader(headerHash, header)) { headerExchanged = true; token.maxAllowedBytes = int.MaxValue; e.UserToken = token; // Ping the server to finalize the player's connection Send(Text.CreateFromString(Time.Timestep, InstanceGuid.ToString(), true, Receivers.Server, MessageGroupIds.NETWORK_ID_REQUEST, true)); } else { // Improper header, so a disconnect is required Disconnect(true); return; } } while (bytesAlreadyProcessed < e.BytesTransferred) { byte[] data = HandleData(e, true, ref bytesAlreadyProcessed); if (data == null) { break; } FrameStream frame = Factory.DecodeMessage(data, false, MessageGroupIds.TCP_FIND_GROUP_ID, Server); FireRead(frame, Server); } DoRead(e); } else { Disconnect(true); } }
/// <summary> /// Infinite loop listening for new data from all connected clients on a separate thread. /// This loop breaks when readThreadCancel is set to true /// </summary> /// <summary> ///无限循环在单独的线程上监听来自所有连接客户端的新数据。 ///当readThreadCancel设置为true时,此循环中断 /// </ summary> private void ReadNetwork() { IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, 0); string incomingEndpoint = string.Empty; try { BMSByte packet = null; // Intentional infinite loop while (IsBound) { //如果读取已被标记为取消,则从此循环中断开 // If the read has been flagged to be canceled then break from this loop if (readThreadCancel) { return; } try { // Read a packet from the network packet = Client.Receive(ref groupEP, ref incomingEndpoint); if (PacketLossSimulation > 0.0f && new Random().NextDouble() <= PacketLossSimulation) { // Skip this message continue; } BandwidthIn += (ulong)packet.Size; } catch (SocketException /*ex*/) { // This is a common exception when we exit the blocking call //Logging.BMSLog.LogException(ex); Disconnect(true); } // Check to make sure a message was received if (packet == null || packet.Size <= 0) { continue; } // This message was not from the server if (groupEP.Address != Server.IPEndPointHandle.Address && groupEP.Port != Server.IPEndPointHandle.Port) { if (packet.Size == 1 && (packet[0] == SERVER_BROADCAST_CODE || packet[1] == CLIENT_BROADCAST_CODE)) { } else if (packet.Size.Between(2, 4) && packet[0] == BROADCAST_LISTING_REQUEST_1 && packet[1] == BROADCAST_LISTING_REQUEST_2 && packet[2] == BROADCAST_LISTING_REQUEST_3) { //这可能是一个本地列表请求,所以用客户端标志字节进行响应 // This may be a local listing request so respond with the client flag byte Client.Send(new byte[] { CLIENT_BROADCAST_CODE }, 1, groupEP); } continue; } // Check to see if the headers have been exchanged if (!headerExchanged) { if (Websockets.ValidateResponseHeader(headerHash, packet.CompressBytes())) { headerExchanged = true; // TODO: When getting the user id, it should also get the server time // by using the current time in the payload and getting it back along with server time // Ping the server to finalize the player's connection Send(Text.CreateFromString(Time.Timestep, InstanceGuid.ToString(), false, Receivers.Server, MessageGroupIds.NETWORK_ID_REQUEST, false), true); } else if (packet.Size != 1 || packet[0] != 0) { Disconnect(true); break; } else { continue; } } else { if (packet.Size < 17) { continue; } // 格式的字节数据到一个udppacket结构 // Format the byte data into a UDPPacket struct UDPPacket formattedPacket = TranscodePacket(Server, packet); // Check to see if this is a confirmation packet, which is just // a packet to say that the reliable packet has been read if (formattedPacket.isConfirmation) { if (formattedPacket.groupId == MessageGroupIds.DISCONNECT) { CloseConnection(); return; } OnMessageConfirmed(server, formattedPacket); continue; } //将数据包添加到管理器,以便可以在完成时跟踪和执行 // Add the packet to the manager so that it can be tracked and executed on complete packetManager.AddPacket(formattedPacket, PacketSequenceComplete, this); } } } catch (Exception ex) { Logging.BMSLog.LogException(ex); Disconnect(true); } }