多年来我一直是Linux上的MPD和GMPC的粉丝。最近承担了建立一个与GMPC外观和感觉相似的网站的任务。作为一名老师,我需要一个 Angular 网站的好例子,这是一个不错的"宠物项目"。
一切都进展顺利,直到我使用命令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 MPDReaders;
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 MPDReadersMPDHTTPReader("localhost","6600");
$api = new mpdInterface($httpreader);
$api->sendCommand($cmd . "n");
$response = $api->connectionReader->readResponse();
$bytesRead = $api->connectionReader->nrOfBytesRead;
没有错误。在16384(16Kb?(之后,数据就停止了。如果我继续阅读,我会收到套接字错误 104(对等方重置连接(。
那么这里出了什么问题呢?
问候马丁
在 MPD 论坛的提示(非常感谢 Max(之后,我让它工作了。命令中有第二个,破坏了协议。新的 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 === "OKn") $end_of_stream = true;
else{
$response .= $buf;
$this->nrOfBytesRead += strlen($buf);
}
}
} while (!$end_of_stream);
return $response;
}//readResponse()