1

私は Linux での MPD と GMPC の数年間のファンです。最近、GMPC に似たルック アンド フィールの Web サイトを構築するタスクを引き受けました。教師として、私はAngular Webサイトの良い例を必要としています.これは素晴らしい「ペットプロジェクト」です.

list Artistコマンドを使用してすべてのアーティストを一覧表示するまで、すべてが順調に進んでい ます。MPC コマンド ライン ツールを次のように使用すると、次のようになります。

mpc list Artist

予想通りたくさんの線が引けます。行数を計算すると、たとえば 1500 人のアーティストが得られます。ただし、PHP とソケット (fsockopen) を使用すると、最大で 16384 しか受信されません。これにより、約 600 ~ 650 のアーティストがリストされます。EOF (feof 関数の使用) を検出し、読み取りを停止します。ソケットを再度開いても役に立ちません。

私は多くのことを試し、最後の MPD バージョン (0.21) をソースから開発マシンにインストールしました (万歳!)。の MPD 設定を無効に変更しましmax_output_buffer_sizeた。新しいバージョンが本当に (/usr/local/bin/mpd から) 開始されたかどうかを確認し、正しい構成ファイル (/etc/mpd.conf) を指定しました。

Music Player Daemon 0.21.13 (0.21.13)
Distributor ID: Ubuntu
Description:    Ubuntu 18.04.3 LTS
Release:    18.04
Codename:   bionic

高レベルの PHP 関数から低レベルのソケットに切り替えました。これは私のコードです:

<?php

  namespace MPD\Readers;

  const BUFFER_LENGTH = 8192 * 1024;

  class MPDConnectionReader
  {

    public $status;
    public $errNo;
    public $errStr;
    public $nrOfBytesRead;
    public $version;

    public function __construct()
    {
      $this->status = "";
      $this->errStr = "";
      $this->errNo = 0;
      $this->nrOfBytesRead = 0;
    }

    public function sendCommand(String $command)
    {
      return null;
    }

    public function readResponse()
    {
      return false;
    }
  }


  class MPDFileReader extends MPDConnectionReader
  {
    private $foldername;

    /**
     * MPDFileReader constructor.
     */
    public function __construct(String $foldername)
    {
      parent::__construct();
      $this->foldername = $foldername;
    }//constructor

    public function sendCommand(String $command)
    {
      return true;
    }
  }


  class MPDHTTPReader extends MPDConnectionReader
  {
    private $_socket;
    private $_host;
    private $_port;

    /**
     * MPDHTTPReader constructor.
     * @param $_host
     * @param $_port
     */
    public function __construct($host, $port)
    {
      parent::__construct();

      $this->_host = $host;
      $this->_port = $port;

      $this->openSocket();
    }//constructor

    private function openSocket()
    {
      $this->_socket = @socket_create(AF_INET, SOCK_STREAM, getprotobyname("tcp"));

      if ($this->_socket === FALSE) $this->handleSocketError("Could not connet");

      $status = @socket_connect($this->_socket, $this->_host, $this->_port);
      if ($status === FALSE) $this->handleSocketError("Could not connect socket");

      // after connect, MPD will send "MPD OK" + version number
      $this->version = socket_read($this->_socket, 2048, PHP_NORMAL_READ);

    }//openSocket()

    private function handleSocketError($functionalDescription)
    {
      $this->errNo = socket_last_error();
      $this->errStr = socket_strerror($this->errNo);
      throw (new \Exception($functionalDescription . "(" . $this->_host . ":" . $this->_port . ") ==> " . $this->errStr, $this->errNo));
    }//handleSocketError()

    public function __destruct()
    {
      if ($this->_socket !== false) socket_close($this->_socket);
    }//__destruct()

    public function sendCommand(String $command)
    {
      $buf = $command . "\n";
      $status = socket_write($this->_socket, $buf);

      if ($status === false) $this->handleSocketError("Could not send to socket");
      else $this->status = "ok";
    }//sendCommand()

    public function readResponse()
    {
      $response = "";
      $end_of_stream = false;

      do {
        $buf = socket_read($this->_socket, BUFFER_LENGTH, PHP_BINARY_READ);

        if ($buf === false) $this->handleSocketError("Could not read from socket");
        elseif ($buf === "") $end_of_stream = true;
        else {
          $response .= $buf;
          $this->nrOfBytesRead += strlen($buf);
        }
      } while (!$end_of_stream);

      return $response;
    }//readResponse()

  }//class

次のように呼び出されます。

$httpreader = new \MPD\Readers\MPDHTTPReader("localhost","6600");
$api = new mpdInterface($httpreader);
$api->sendCommand($cmd . "\n");

$response = $api->connectionReader->readResponse();
$bytesRead = $api->connectionReader->nrOfBytesRead;

エラーはありません。16384 (16Kb?) の後、正確にデータが来なくなります。読み続けると、ソケット エラー 104 (ピアによる接続のリセット) が発生します。

ここで何が問題なのですか?

こんにちはマーティン

4

1 に答える 1

1

MPD フォーラム (Max に感謝) からのヒントの後、私はそれを機能させました。コマンドに 2 番目の \n があり、プロトコルが壊れています。新しい readResponse 関数は以下のとおりです。socket_read()の代わりに関数を使用していることに注意してください。 socket_recv改善のための作業がありますが、この質問に答えるために、次のようにします。

public function readResponse()
{
  $response = "";
  $end_of_stream = false;

  do {
    $buf = socket_read($this->_socket, BUFFER_LENGTH, PHP_NORMAL_READ);

    if ($buf === "") $end_of_stream = true;
    elseif ($buf === false) $this->handleSocketError("Could not read from socket");
    else {
      if ($buf === "OK\n") $end_of_stream = true;
      else{
        $response .= $buf;
        $this->nrOfBytesRead += strlen($buf);
      }
    }
  } while (!$end_of_stream);

  return $response;
}//readResponse()
于 2019-08-22T07:45:38.750 に答える