/// <summary>Sends a message of the specified type, with the specified data.</summary> /// <param name="type">The type of the message to send.</param> /// <param name="packet">The data to send.</param> protected override void Send(SessionMessage type, IWritablePacket packet = null) { if (ConnectionState != ClientState.Connected) { throw new InvalidOperationException("Not in a session."); } try { using (var wrapper = new Packet()) { wrapper.Write((byte)type).Write(packet); var written = _stream.Write(wrapper); // Statistics. Info.PutOutgoingTraffic( written, type == SessionMessage.Data ? TrafficTypes.Data : TrafficTypes.Protocol); Info.PutOutgoingPacketSize(written); if (packet != null) { Info.PutOutgoingPacketCompression((packet.Length / (float)written) - 1f); } } } catch (IOException ex) { Logger.TraceException("Socket connection died.", ex); Reset(); } }
/// <summary>Join a local game.</summary> /// <param name="server">the local server to join.</param> /// <param name="playerName">the name with which to register.</param> /// <param name="playerData">additional data to be associated with our player.</param> public void Join(IServerSession server, string playerName, object playerData) { if (ConnectionState != ClientState.Unconnected) { throw new InvalidOperationException("Must leave the current session first."); } if (!(server is HybridServerSession <TPlayerData>)) { throw new InvalidOperationException("Incompatible server type."); } if (!(playerData is TPlayerData)) { throw new ArgumentException("Invalid type.", "playerData"); } Logger.Debug("Begin connecting to local server."); _playerName = playerName; _playerData = (TPlayerData)playerData; ConnectionState = ClientState.Connecting; // Check if the server is already full. if (server.PlayerCount >= server.MaxPlayers) { Logger.Debug("Join failed, server already full."); Reset(); return; } // Create the two 'pipes' we use to pass data from client to server // and vice versa. var toClient = new SlidingStream(); var toServer = new SlidingStream(); // Our stream is the one where the sink is the server. // The server gets one in the other direction (see below). _stream = new SlidingPacketStream(toClient, toServer); using (var packet = new Packet()) { using (var packetInner = new Packet()) { packetInner. Write(_playerName). Write(_playerData); packet. Write((byte)SessionMessage.JoinRequest). Write((IWritablePacket)packetInner); var written = _stream.Write(packet); // Statistics. Info.PutOutgoingTraffic(written, TrafficTypes.Protocol); Info.PutOutgoingPacketSize(written); Info.PutOutgoingPacketCompression((packet.Length / (float)written) - 1f); } } // Let's try this. This can throw if the server is already // full, but that shouldn't happen, because we checked above. ((HybridServerSession <TPlayerData>)server). Add(new SlidingPacketStream(toServer, toClient)); }
/// <summary> /// Writes the specified packet to the underlying stream. It can then be read byte a <c>PacketStream</c> on the other /// end of the stream. /// </summary> /// <param name="packet">The packet to write.</param> /// <returns> /// The number of bytes actually written. This can differ from the length of the specified packet due to /// transforms from wrapper streams (encryption, compression, ...) /// </returns> /// <exception cref="System.IO.IOException">If the underlying stream fails.</exception> public int Write(IWritablePacket packet) { using (var data = new Packet()) { data.Write(Crypto.Encrypt(packet.GetBuffer(), 0, packet.Length)); return(_stream.Write(data)); } }
/// <summary>Connected successfully to the server, send login data.</summary> private void HandleConnected(IAsyncResult result) { lock (this) { if (_tcp == null) { return; } try { Logger.Debug("Connected to host, sending actual join request."); _tcp.EndConnect(result); _stream = new EncryptedPacketStream(new CompressedPacketStream(new NetworkPacketStream(_tcp.GetStream()))); using (var packet = new Packet()) { using (var packetInner = new Packet()) { packetInner. Write(_playerName). Write(_playerData); packet. Write((byte)SessionMessage.JoinRequest). Write((IWritablePacket)packetInner); var written = _stream.Write(packet); // Statistics. Info.PutOutgoingTraffic(written, TrafficTypes.Protocol); Info.PutOutgoingPacketSize(written); Info.PutOutgoingPacketCompression((packet.Length / (float)written) - 1f); } } } catch (SocketException ex) { // Connection failed. Logger.DebugException("Join failed.", ex); _resetRequested = true; } } }
/// <summary> /// Writes the specified packet to the underlying stream. It can then be read /// byte a <c>PacketStream</c> on the other end of the stream. /// </summary> /// <param name="packet">The packet to write.</param> /// <returns>The number of bytesa actually written. This can differ /// from the length of the specified packet due to transforms from /// wrapper streams (encryption, compression, ...)</returns> /// <exception cref="System.IO.IOException">If the underlying stream fails.</exception> public int Write(IWritablePacket packet) { using (var data = new Packet()) { // If packets are large, try compressing them, see if it helps. // Only start after a certain size. General overhead for gzip // seems to be around 130byte, so make sure we're well beyond that. byte[] compressed; if (packet.Length > 200 && (compressed = SimpleCompression.Compress(packet.GetBuffer(), packet.Length)).Length < packet.Length) { // OK, worth it, it's smaller than before. data.Write(true); data.Write(compressed); } else { data.Write(false); data.Write(packet.GetBuffer(), 0, packet.Length); } return(_stream.Write(data)); } }