public function sendFrame($payload, $type = Pool::TYPE_TEXT, $isMasked = true)
    {
        $payloadLength = mb_orig_strlen($payload);
        if ($payloadLength > $this->pool->maxAllowedPacket) {
            Daemon::$process->log('max-allowed-packet (' . $this->pool->config->maxallowedpacket->getHumanValue() . ') exceed, aborting connection');
            return;
        }

        $firstByte = '';
        switch ($type) {
            case Pool::TYPE_TEXT:
                $firstByte = 129;
                break;
            case Pool::TYPE_CLOSE:
                $firstByte = 136;
                break;
            case Pool::TYPE_PING:
                $firstByte = 137;
                break;
            case Pool::TYPE_PONG:
                $firstByte = 138;
                break;
        }

        $hdrPacket = chr($firstByte);

        $isMaskedInt = $isMasked ? 128 : 0;
        if ($payloadLength <= 125) {
            $hdrPacket .= chr($payloadLength + $isMaskedInt);
        } elseif ($payloadLength <= 65535) {
            $hdrPacket .= chr(126 + $isMaskedInt) . // 126 + 128
                chr($payloadLength >> 8) .
                chr($payloadLength & 0xFF);
        } else {
            $hdrPacket .= chr(127 + $isMaskedInt) . // 127 + 128
                chr($payloadLength >> 56) .
                chr($payloadLength >> 48) .
                chr($payloadLength >> 40) .
                chr($payloadLength >> 32) .
                chr($payloadLength >> 24) .
                chr($payloadLength >> 16) .
                chr($payloadLength >> 8) .
                chr($payloadLength & 0xFF);
        }
        $this->write($hdrPacket);
        if ($isMasked) {
            $this->write($mask = chr(mt_rand(0, 0xFF)) .
                chr(mt_rand(0, 0xFF)) .
                chr(mt_rand(0, 0xFF)) .
                chr(mt_rand(0, 0xFF)));
            $this->write(static::mask($mask, $payload));
        } else {
            $this->write($payload);
        }
    }