zhouaini528 / binance-php

Binance API Like the official document interface, Support for arbitrary extension.
MIT License
107 stars 43 forks source link

websocket server运行一段时间后空数据 #58

Closed douno23 closed 5 months ago

douno23 commented 6 months ago

使用websocket方式,在请求一段时间后,返回空数据 用demo中的案例即可重现 烦请排查

douno23 commented 5 months ago

image

是这个原因吗?

zhouaini528 commented 5 months ago

那个不是原因。你程序运行好久 就开始空数据了? 是订阅行情对吧?

zhouaini528 commented 5 months ago

以下是官方文档

Websocket 行情推送
本篇所列出的所有 wss 接口的 base URL 为: wss://stream.binance.com:9443 或者 wss://stream.binance.com:443
Streams 有单一原始 stream 或组合 stream。
用户可以侦听/订阅数个数据流。
单一原始 streams 格式为 /ws/<streamName>
组合 streams 的 URL 格式为 /stream?streams=<streamName1>/<streamName2>/<streamName3>
订阅组合 streams 时,事件 payload 会以这样的格式封装: {"stream":"<streamName>","data":<rawPayload>}
stream 名称中所有交易对均为 小写。
每个到 stream.binance.com 的链接有效期不超过24小时,请妥善处理断线重连。
Websocket 服务器每3分钟发送Ping消息。
如果Websocket服务器在10分钟之内没有收到Pong消息应答,连接会被断开。
当客户收到ping消息,必需尽快回复pong消息,同时payload需要和ping消息一致。
未经请求的pong消息是被允许的,但是不会保证连接不断开。对于这些pong消息,建议payload为空
wss://data-stream.binance.vision 可以用来订阅仅有市场信息的数据流。账户信息无法从此 URL 获得。

最重要的两句: 1:每个到 stream.binance.com 的链接有效期不超过24小时,请妥善处理断线重连。

2:当客户收到ping消息,必需尽快回复pong消息,同时payload需要和ping消息一致。

第一个问题 我的程序有重连机制 但是建议你自己也要有一个重连机制, 第二个问题 我正在查看,但是测试也没发现问题。 我再去试试。

程序必须要有一个公共订阅的行情才不会自动断开。不然每60秒会自动断开 再重连

douno23 commented 5 months ago

以下是官方文档

Websocket 行情推送
本篇所列出的所有 wss 接口的 base URL 为: wss://stream.binance.com:9443 或者 wss://stream.binance.com:443
Streams 有单一原始 stream 或组合 stream。
用户可以侦听/订阅数个数据流。
单一原始 streams 格式为 /ws/<streamName>
组合 streams 的 URL 格式为 /stream?streams=<streamName1>/<streamName2>/<streamName3>
订阅组合 streams 时,事件 payload 会以这样的格式封装: {"stream":"<streamName>","data":<rawPayload>}
stream 名称中所有交易对均为 小写。
每个到 stream.binance.com 的链接有效期不超过24小时,请妥善处理断线重连。
Websocket 服务器每3分钟发送Ping消息。
如果Websocket服务器在10分钟之内没有收到Pong消息应答,连接会被断开。
当客户收到ping消息,必需尽快回复pong消息,同时payload需要和ping消息一致。
未经请求的pong消息是被允许的,但是不会保证连接不断开。对于这些pong消息,建议payload为空
wss://data-stream.binance.vision 可以用来订阅仅有市场信息的数据流。账户信息无法从此 URL 获得。

最重要的两句: 1:每个到 stream.binance.com 的链接有效期不超过24小时,请妥善处理断线重连。

2:当客户收到ping消息,必需尽快回复pong消息,同时payload需要和ping消息一致。

第一个问题 我的程序有重连机制 但是建议你自己也要有一个重连机制, 第二个问题 我正在查看,但是测试也没发现问题。 我再去试试。

程序必须要有一个公共订阅的行情才不会自动断开。不然每60秒会自动断开 再重连

几十分钟就会没有消息了 订阅了公共频道

  1. server.php
    
    require 'vendor/autoload.php';
    require 'support/bootstrap.php';

use Lin\Binance\BinanceWebSocket;

$binance = new BinanceWebSocket();

$binance->config([ //是否开启日志,默认未开启 false 'log' => true, //或者设置日志名称,默认按照日期保存 'log' => ['filename' => 'runtime/binance/spot'],

//进程服务端口地址,默认 0.0.0.0:2208
//'global'=>'127.0.0.1:2208',

//心跳时间,默认 20 秒
//'ping_time'=>20,

//订阅新的频道监控时间, 默认 2 秒
//'listen_time'=>2,

//频道数据更新时间,默认 0.1 秒
//'data_time'=>0.1,

//私有数据队列默认保存100条
//'queue_count'=>100,

//baseurl
'baseurl' => 'ws://stream.binance.com:9443',//默认现货
//'baseurl'=>'ws://fstream.binance.com',//usdt期货
//'baseurl'=>'ws://dstream.binance.com',//币本位期货

]); $binance->start();


2. client.php
```<?php
require 'vendor/autoload.php';
require 'support/bootstrap.php';

use app\utils\Functions;
use Lin\Binance\BinanceWebSocket;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Output\ConsoleOutput;

/**
 * @return void
 * @throws \Longman\TelegramBot\Exception\TelegramException
 */
function core() {
    $binance = new BinanceWebSocket();
    $out     = new ConsoleOutput();

    $binance->config([
        //是否开启日志,默认未开启 false
        'log'     => true,
        //或者设置日志名称,默认按照日期保存
        //'log'=>['filename'=>'spot'],

        //进程服务端口地址,默认 0.0.0.0:2208
        //'global'=>'127.0.0.1:2208',

        //心跳时间,默认 20 秒
        //'ping_time'=>20,

        //订阅新的频道监控时间, 默认 2 秒
        //'listen_time'=>2,

        //频道数据更新时间,默认 0.1 秒
        //'data_time'=>0.1,

        //私有数据队列默认保存100条
        //'queue_count'=>100,

        //baseurl
        'baseurl' => 'ws://stream.binance.com:9443',//默认现货
        //'baseurl'=>'ws://fstream.binance.com',//usdt期货
        //'baseurl'=>'ws://dstream.binance.com',//币本位期货
    ]);

    // K线stream逐秒推送所请求的K线种类
    $coins = [
        'btcusdt@kline_5m'  => 'BTCUSDT',
        'ethusdt@kline_5m'  => 'ETHUSDT',
        'bnbusdt@kline_5m'  => 'BNBUSDT',
        'dogeusdt@kline_5m' => 'DOGEUSDT',
        'shibusdt@kline_5m' => 'SHIBUSDT',
    ];

    // 订阅币种 K 线
    $subscribes = array_keys($coins);
    $binance->subscribe($subscribes);

    $table = new Table($out);

    // 初始化
    $need_sleep        = true;
    $time_limit_second = 1;
    $start             = time();
    while (true) {
        pcntl_alarm(0);
        if ($need_sleep) {
            sleep($time_limit_second);
        }
        try {
            $data = $binance->getSubscribes();
            if (empty($data)) {
                $message = '[' . date('Y-m-d H:i:s', $start) . ' ~ ' . date('Y-m-d H:i:s') . '] 异常数据 ' . Functions::jsonEncode($data) . "\r\n";
                $out->writeln($message);
                file_put_contents('error.log', $message, FILE_APPEND);
            }
            $console_message = date('Y-m-d H:i:s');
            $out->writeln($console_message);
            foreach ($data as $key => $value) {
                $symbol = $coins[$key] ?? '';
                if (empty($symbol)) {
                    $console_message = '[' . $key . '] 无数据';
                    $out->writeln($console_message);
                    continue;
                }

                $detail = $value['data'] ?? [];
                if (empty($detail)) {
                    $console_message = '[' . $symbol . '] 无数据';
                    $out->writeln($console_message);
                    continue;
                }
                $k_time     = $detail['E'] ?? 0;
                $k          = $detail['k'] ?? [];
                $begin_time = $k['t'] ?? 0;
                $end_time   = $k['T'] ?? 0;
                $now        = microtime(true);
                // 如果 K 线已经过期 1 秒,就丢弃
                $expire_time = $now - $k_time;
                if ($expire_time > $time_limit_second * 1000) {
                    $console_message = '[' . $symbol . '] K线时间已过:' . $expire_time . 'ms';
                    $out->writeln($console_message);
                    $need_sleep = false;
                    continue;
                }

                $open_price       = $k['o'];
                $close_price      = $k['c'];
                $high_price       = $k['h'];
                $low_price        = $k['l'];
                $extent_of_a_drop = 1 - ($close_price / $high_price);
                $percent          = $extent_of_a_drop * 100;

                $headers = ['币种', '涨跌幅', 'K线时间', '开盘价', '收盘价', '最高价', '最低价'];
                $table->setHeaders($headers);
                $rows = [
                    [
                        $symbol,
                        ($extent_of_a_drop > 1 ? '+' : '-') . $percent . '%',
                        date('Y-m-d H:i:s', (int)($k_time / 1000)),
                        $open_price,
                        $close_price,
                        $high_price,
                        $low_price,
                    ],
                ];
                $table->setRows($rows);
                $table->render();
            }
        } catch (Exception $exception) {
            $console_message = '[ 异常 ] ' . $exception->getMessage() . ' 文件:' . $exception->getFile() . ' 行:' . $exception->getLine() . ' 数据:' . Functions::jsonEncode($data);
            var_dump($exception->getTrace());
            $out->writeln($console_message);
        }
    }
}

core();

return;
douno23 commented 5 months ago

系统: macOS 14.4 PHP环境: PHP 8.2.12 (cli) (built: Oct 24 2023 19:22:16) (NTS) webman版本: Webman-framework v1.5.16

douno23 commented 5 months ago

是个乌龙事件,目前怀疑是电脑自动休眠了,也是很巧,我的服务器被误判为在屏蔽地区,目前使用笔记本电脑执行程序,应该是触发了笔记本电脑的休眠节能机制。

另外期待你关于 ping 的处理

打扰了,并且非常感谢

zhouaini528 commented 5 months ago

是个乌龙事件,目前怀疑是电脑自动休眠了,也是很巧,我的服务器被误判为在屏蔽地区,目前使用笔记本电脑执行程序,应该是触发了笔记本电脑的休眠节能机制。

另外期待你关于 ping 的处理

打扰了,并且非常感谢

我刚刚都还在测试中, 建议你购买一个云服务器测试。

根据文档: Websocket 服务器每3分钟发送Ping消息。 如果Websocket服务器在10分钟之内没有收到Pong消息应答,连接会被断开。 当客户收到ping消息,必需尽快回复pong消息,同时payload需要和ping消息一致。

我测试就没有收到过该信息, 看来需要多测试一下。

douno23 commented 5 months ago

是个乌龙事件,目前怀疑是电脑自动休眠了,也是很巧,我的服务器被误判为在屏蔽地区,目前使用笔记本电脑执行程序,应该是触发了笔记本电脑的休眠节能机制。 另外期待你关于 ping 的处理 打扰了,并且非常感谢

我刚刚都还在测试中, 建议你购买一个云服务器测试。

根据文档: Websocket 服务器每3分钟发送Ping消息。 如果Websocket服务器在10分钟之内没有收到Pong消息应答,连接会被断开。 当客户收到ping消息,必需尽快回复pong消息,同时payload需要和ping消息一致。

我测试就没有收到过该信息, 看来需要多测试一下。

其实是购买了韩国的云服务器,但是被币安误判为在限制国家地区,无法使用。 目前已经使用微型主机安装了centos执行脚本了,目前运行没有问题。

你有小飞机吗,加你请教沟通交流一下币圈的一些事情

douno23 commented 5 months ago

是个乌龙事件,目前怀疑是电脑自动休眠了,也是很巧,我的服务器被误判为在屏蔽地区,目前使用笔记本电脑执行程序,应该是触发了笔记本电脑的休眠节能机制。 另外期待你关于 ping 的处理 打扰了,并且非常感谢

我刚刚都还在测试中, 建议你购买一个云服务器测试。

根据文档: Websocket 服务器每3分钟发送Ping消息。 如果Websocket服务器在10分钟之内没有收到Pong消息应答,连接会被断开。 当客户收到ping消息,必需尽快回复pong消息,同时payload需要和ping消息一致。

我测试就没有收到过该信息, 看来需要多测试一下。

我尝试着打开了你注释的那行ping,但是币安返回报错了,应该是消息格式不符合标准

zhouaini528 commented 5 months ago

小飞机 有,但是不咋个用, 你加QQ群 668421169