/// <summary> /// The server sent us a message before sending a response header to validate /// This happens if the server is not accepting connections or the max connection count has been reached /// We will get two messages. The first one is either a MAX_CONNECTIONS or NOT_ACCEPT_CONNECTIONS group message. /// The second one will be the DISCONNECT message /// </summary> /// <param name="packet">The packet recieved causing relating to the rejection</param> private void HandleServerRejection(BMSByte packet) { UDPPacket formattedPacket = TranscodePacket(ServerPlayer, packet); if (formattedPacket.groupId == MessageGroupIds.MAX_CONNECTIONS) { Logging.BMSLog.LogWarning("Max Players Reached On Server"); } else if (formattedPacket.groupId == MessageGroupIds.NOT_ACCEPT_CONNECTIONS) { Logging.BMSLog.LogWarning("The server is busy and not accepting connections"); } else if (formattedPacket.groupId == MessageGroupIds.DISCONNECT) { CloseConnection(); } else { // Received something unexpected so do the same thing as the if below Disconnect(true); CancelReadThread(); } }
/// <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> private void ReadNetwork() { CSteamID messageFrom = default(CSteamID); 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 { uint msgSize = 0; if (SteamNetworking.IsP2PPacketAvailable(out msgSize)) { packet = Client.Receive(msgSize, out messageFrom); } else { Thread.Sleep(1); continue; } // Read a packet from the network 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; } // 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) { Logging.BMSLog.LogWarning("DISCONNECTED: RECEIVED UNKNOWN PACKET BEFORE HEADERS WERE EXCHANGED!"); Disconnect(true); break; } else { continue; } } else { if (packet.Size < 17) { continue; } // 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); } }
/// <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> 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 >= MINIMUM_FRAME_SIZE) { // The server sent us a message before sending a responseheader to validate // This happens if the server is not accepting connections or the max connection count has been reached // We will get two messages. The first one is either a MAX_CONNECTIONS or NOT_ACCEPT_CONNECTIONS group message. // The second one will be the DISCONNECT message UDPPacket formattedPacket = TranscodePacket(Server, packet); if (formattedPacket.groupId == MessageGroupIds.MAX_CONNECTIONS) { Logging.BMSLog.LogWarning("Max Players Reached On Server"); // Wait for the second message (Disconnect) continue; } if (formattedPacket.groupId == MessageGroupIds.NOT_ACCEPT_CONNECTIONS) { Logging.BMSLog.LogWarning("The server is busy and not accepting connections"); // Wait for the second message (Disconnect) continue; } if (formattedPacket.groupId == MessageGroupIds.DISCONNECT) { CloseConnection(); return; } // Received something unexpected so do the same thing as the if below Disconnect(true); break; } else if (packet.Size != 1 || packet[0] != 0) { Disconnect(true); break; } else { continue; } } else { if (packet.Size < MINIMUM_FRAME_SIZE) { continue; } // 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; } if (formattedPacket.groupId == MessageGroupIds.AUTHENTICATION_FAILURE) { Logging.BMSLog.LogWarning("The server rejected the authentication attempt"); // Wait for the second message (Disconnect) 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); } }
private bool IsDisconnectableGroupId(UDPPacket formattedPacket) { return(formattedPacket.groupId == MessageGroupIds.DISCONNECT || formattedPacket.groupId == MessageGroupIds.AUTHENTICATION_FAILURE); }
/// <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); } }