You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求基于PHP标准Socket函数的SignalR客户端示例(对接socket.bittrex.com)

PHP Standard Socket SignalR Client for Bittrex

Hey Marcel, great job getting the initial connection to Bittrex's SignalR socket working! Let's break down exactly how to subscribe to topics and process those real-time updates using PHP's built-in socket functions. Bittrex uses SignalR over WebSockets with the JSON protocol, so we'll need to handle WebSocket framing, SignalR handshake, subscription messages, and incoming update parsing.

Step 1: Confirm the WebSocket Handshake

Since you already got a "Success" response, you probably have this covered, but let's recap to make sure. First, you need to initiate a WebSocket connection to Bittrex's SignalR endpoint. Here's the basic handshake code:

$socket = stream_socket_client('ssl://socket.bittrex.com:443', $errno, $errstr, 30);
if (!$socket) {
    die("$errstr ($errno)");
}

$handshakeKey = base64_encode(random_bytes(16));
$handshake = "GET /signalr/connect?transport=webSockets&clientProtocol=1.5 HTTP/1.1\r\n";
$handshake .= "Host: socket.bittrex.com\r\n";
$handshake .= "Upgrade: websocket\r\n";
$handshake .= "Connection: Upgrade\r\n";
$handshake .= "Sec-WebSocket-Key: $handshakeKey\r\n";
$handshake .= "Sec-WebSocket-Version: 13\r\n\r\n";

fwrite($socket, $handshake);
$response = fread($socket, 1024);

// Verify we got the correct handshake response
if (strpos($response, '101 Switching Protocols') === false) {
    die("Handshake failed: $response");
}

Step 2: Send a SignalR Subscription Message

Once connected, you need to send a JSON-formatted message to subscribe to your target market (like BTC-USD). First, let's create a helper function to pack messages into valid WebSocket frames:

function webSocketEncode($data) {
    $length = strlen($data);
    $frame = chr(0x81); // FIN flag + Text frame type

    if ($length <= 125) {
        $frame .= chr($length);
    } elseif ($length > 125 && $length < 65536) {
        $frame .= chr(126);
        $frame .= pack('n', $length);
    } else {
        $frame .= chr(127);
        $frame .= pack('J', $length);
    }

    return $frame . $data;
}

Now send the subscription message to Bittrex's c2 hub (their official SignalR hub name):

$subscribeMsg = json_encode([
    'H' => 'c2',          // Bittrex's SignalR hub name
    'M' => 'SubscribeToExchangeDeltas', // Subscription method
    'A' => ['BTC-USD'],  // Array of markets to subscribe to
    'I' => 1             // Unique message ID (can be any integer)
]);

fwrite($socket, webSocketEncode($subscribeMsg));

Step 3: Listen for and Process Real-Time Updates

Next, we need a helper to decode incoming WebSocket frames, then set up a loop to listen for updates:

function webSocketDecode($data) {
    $length = ord($data[1]) & 127;
    if ($length == 126) {
        $payloadOffset = 4;
        $payloadLength = unpack('n', substr($data, 2, 2))[1];
    } elseif ($length == 127) {
        $payloadOffset = 10;
        $payloadLength = unpack('J', substr($data, 2, 8))[1];
    } else {
        $payloadOffset = 2;
        $payloadLength = $length;
    }

    return substr($data, $payloadOffset, $payloadLength);
}

// Start listening for updates
echo "Listening for Bittrex BTC-USD updates...\n\n";
while (!feof($socket)) {
    $buffer = fread($socket, 4096);
    if (empty($buffer)) continue;

    $decodedMsg = webSocketDecode($buffer);
    if (empty($decodedMsg)) continue;

    $signalRData = json_decode($decodedMsg, true);
    if (!$signalRData) continue;

    // Process real-time update messages
    if (isset($signalRData['M'])) {
        foreach ($signalRData['M'] as $method) {
            if ($method['M'] == 'updateExchangeState') {
                $marketUpdate = $method['A'][0];
                echo date('Y-m-d H:i:s') . " | {$marketUpdate['MarketName']}\n";
                echo "Bid: {$marketUpdate['Bid']} | Ask: {$marketUpdate['Ask']} | Last Trade: {$marketUpdate['Last']}\n";
                echo "-------------------------\n";
            }
        }
    }
}

fclose($socket);

Full Working Example

Putting it all together, here's a complete script you can run:

<?php

function webSocketEncode($data) {
    $length = strlen($data);
    $frame = chr(0x81);

    if ($length <= 125) {
        $frame .= chr($length);
    } elseif ($length > 125 && $length < 65536) {
        $frame .= chr(126);
        $frame .= pack('n', $length);
    } else {
        $frame .= chr(127);
        $frame .= pack('J', $length);
    }

    return $frame . $data;
}

function webSocketDecode($data) {
    $length = ord($data[1]) & 127;
    if ($length == 126) {
        $payloadOffset = 4;
        $payloadLength = unpack('n', substr($data, 2, 2))[1];
    } elseif ($length == 127) {
        $payloadOffset = 10;
        $payloadLength = unpack('J', substr($data, 2, 8))[1];
    } else {
        $payloadOffset = 2;
        $payloadLength = $length;
    }

    return substr($data, $payloadOffset, $payloadLength);
}

// Initialize connection
$socket = stream_socket_client('ssl://socket.bittrex.com:443', $errno, $errstr, 30);
if (!$socket) {
    die("$errstr ($errno)");
}

// Perform WebSocket handshake
$handshakeKey = base64_encode(random_bytes(16));
$handshake = "GET /signalr/connect?transport=webSockets&clientProtocol=1.5 HTTP/1.1\r\n";
$handshake .= "Host: socket.bittrex.com\r\n";
$handshake .= "Upgrade: websocket\r\n";
$handshake .= "Connection: Upgrade\r\n";
$handshake .= "Sec-WebSocket-Key: $handshakeKey\r\n";
$handshake .= "Sec-WebSocket-Version: 13\r\n\r\n";

fwrite($socket, $handshake);
$response = fread($socket, 1024);

if (strpos($response, '101 Switching Protocols') === false) {
    die("Handshake failed: $response");
}

// Send subscription message
$subscribeMsg = json_encode([
    'H' => 'c2',
    'M' => 'SubscribeToExchangeDeltas',
    'A' => ['BTC-USD'],
    'I' => 1
]);
fwrite($socket, webSocketEncode($subscribeMsg));

// Listen for updates
echo "Listening for Bittrex updates...\n\n";
while (!feof($socket)) {
    $buffer = fread($socket, 4096);
    if (empty($buffer)) continue;

    $decoded = webSocketDecode($buffer);
    if (empty($decoded)) continue;

    $signalRMsg = json_decode($decoded, true);
    if (!$signalRMsg) continue;

    if (isset($signalRMsg['M'])) {
        foreach ($signalRMsg['M'] as $method) {
            if ($method['M'] == 'updateExchangeState') {
                $data = $method['A'][0];
                echo date('Y-m-d H:i:s') . " | {$data['MarketName']}\n";
                echo "Bid: {$data['Bid']} | Ask: {$data['Ask']} | Last: {$data['Last']}\n";
                echo "-------------------------\n";
            }
        }
    }
}

fclose($socket);
?>

Quick Notes

  • Other Subscription Methods: Try SubscribeToSummaryDeltas for market summary updates, or SubscribeToOrderBookDeltas for order book changes—just adjust the M value in the subscription message.
  • Error Handling: Add reconnection logic if the socket drops, and validate JSON responses to avoid crashes.
  • Rate Limits: Bittrex enforces SignalR connection limits, so avoid spamming subscription requests.

内容的提问来源于stack exchange,提问作者Marcel Molenaar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 09:16:05