/** This method is thread safe. */
  public int send(Connection connection, Object object) throws IOException {
    SocketChannel socketChannel = this.socketChannel;
    if (socketChannel == null) throw new SocketException("Connection is closed.");
    synchronized (writeLock) {
      // Leave room for length.
      int start = writeBuffer.position();
      int lengthLength = serialization.getLengthLength();
      writeBuffer.position(writeBuffer.position() + lengthLength);

      // Write data.
      try {
        serialization.write(connection, writeBuffer, object);
      } catch (KryoNetException ex) {
        throw new KryoNetException(
            "Error serializing object of type: " + object.getClass().getName(), ex);
      }
      int end = writeBuffer.position();

      // Write data length.
      writeBuffer.position(start);
      serialization.writeLength(writeBuffer, end - lengthLength - start);
      writeBuffer.position(end);

      // Write to socket if no data was queued.
      if (start == 0 && !writeToSocket()) {
        // A partial write, set OP_WRITE to be notified when more writing can occur.
        selectionKey.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);
      } else {
        // Full write, wake up selector so idle event will be fired.
        selectionKey.selector().wakeup();
      }

      if (DEBUG || TRACE) {
        float percentage = writeBuffer.position() / (float) writeBuffer.capacity();
        if (DEBUG && percentage > 0.75f)
          debug(
              "kryonet",
              connection + " TCP write buffer is approaching capacity: " + percentage + "%");
        else if (TRACE && percentage > 0.25f)
          trace("kryonet", connection + " TCP write buffer utilization: " + percentage + "%");
      }

      lastWriteTime = System.currentTimeMillis();
      return end - start;
    }
  }
  /** This method is thread safe. */
  public int send(Connection connection, Object json, SocketAddress address) throws IOException {
    DatagramChannel datagramChannel = this.datagramChannel;
    if (datagramChannel == null) throw new SocketException("Connection is closed.");
    synchronized (writeLock) {
      try {
        try {
          serialization.write(connection, writeBuffer, json);
        } catch (Exception ex) {
          throw new DiDiNetException("Error serializing object of type: " + json, ex);
        }
        writeBuffer.flip();
        int length = writeBuffer.limit();
        datagramChannel.send(writeBuffer, address);

        lastCommunicationTime = System.currentTimeMillis();

        boolean wasFullWrite = !writeBuffer.hasRemaining();
        return wasFullWrite ? length : -1;
      } finally {
        writeBuffer.clear();
      }
    }
  }