我已经使用Ratchet在本地MAMP PRO环境中通过php设置了一个websocket服务器。
$server = IoServer::factory(
new Control(),
81,
'0.0.0.0'
);
使用root特权启动服务器(因为除root特权外,我无法使他正常运行(权限被拒绝))
php server.php
建立连接
telnet 192.168.2.106 81
Trying 192.168.2.106...
Connected to mmm.mrmedia.private.
正确回答
php server.php
New connection! (37)
但是,如果我尝试通过JavaScript连接到服务器,则不会通过握手(过了一段时间后会出现ERR_CONNECTION_REFUSED)。
New connection! (48)
Connection 48 sending message "GET / HTTP/1.1
Host: 192.168.2.106:81
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36
Upgrade: websocket
Origin: http://192.168.2.106
Sec-WebSocket-Version: 13
Accept-Encoding: gzip, deflate
Accept-Language: de,de-DE;q=0.9,en;q=0.8,en-US;q=0.7,es;q=0.6,fr;q=0.5,it;q=0.4
Sec-WebSocket-Key: RH25+2UD8PQI+0A+VQWn4Q==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
控制台输出以下信息:
TIC TCP Conn Start [24126:0x7fdcc6f47c20]
TIC TCP Conn Event [24126:0x7fdcc6f47c20]: 3
TIC TCP Conn Failed [24126:0x7fdcc6f47c20]: 12:8 Err(-65554)
TIC TCP Conn Cancel [24126:0x7fdcc6f47c20]
源server.php
use Ratchet\Server\IoServer;
use FluvalEdge\Control;
require dirname(__DIR__) . '/websocket-php-ratchet/vendor/autoload.php';
$server = IoServer::factory(
new Control(),
81,
'0.0.0.0'
);
$server->run();
源名称间隔FluvalEdge
namespace FluvalEdge;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
class Control implements MessageComponentInterface {
protected $clients;
public function __construct() {
$this->clients = new \SplObjectStorage;
}
public function onOpen(ConnectionInterface $conn) {
// Store the new connection to send messages to later
$this->clients->attach($conn);
echo "New connection! ({$conn->resourceId})\n";
}
public function onMessage(ConnectionInterface $from, $msg) {
$numRecv = count($this->clients) - 1;
echo sprintf('Connection %d sending message "%s" to %d other connection%s' . "\n"
, $from->resourceId, $msg, $numRecv, $numRecv == 1 ? '' : 's');
foreach ($this->clients as $client) {
if ($from !== $client) {
// The sender is not the receiver, send to each client connected
$client->send($msg);
}
}
}
public function onClose(ConnectionInterface $conn) {
// The connection is closed, remove it, as we can no longer send it messages
$this->clients->detach($conn);
echo "Connection {$conn->resourceId} has disconnected\n";
}
public function onError(ConnectionInterface $conn, \Exception $e) {
echo "An error has occurred: {$e->getMessage()}\n";
$conn->close();
}
}
通过调用客户端连接
initWebsocket('ws://192.168.2.106:81', false, 5000, 5);
源websocket.js
/**
* inits a websocket by a given url, returned promise resolves with initialized websocket, rejects after failure/timeout.
*
* @param url the websocket url to init
* @param existingWebsocket if passed and this passed websocket is already open, this existingWebsocket is resolved, no additional websocket is opened
* @param timeoutMs the timeout in milliseconds for opening the websocket
* @param numberOfRetries the number of times initializing the socket should be retried, if not specified or 0, no retries are made
* and a failure/timeout causes rejection of the returned promise
* @return {Promise}
*/
function initWebsocket(url, existingWebsocket, timeoutMs, numberOfRetries) {
timeoutMs = timeoutMs ? timeoutMs : 1500;
numberOfRetries = numberOfRetries ? numberOfRetries : 0;
var hasReturned = false;
var promise = new Promise((resolve, reject) => {
setTimeout(function () {
if(!hasReturned) {
console.info('opening websocket timed out: ' + url);
rejectInternal();
}
}, timeoutMs);
if (!existingWebsocket || existingWebsocket.readyState != existingWebsocket.OPEN) {
if (existingWebsocket) {
existingWebsocket.close();
}
var websocket = new WebSocket(url);
websocket.onopen = function () {
if(hasReturned) {
websocket.close();
} else {
console.info('websocket to opened! url: ' + url);
resolve(websocket);
}
};
websocket.onclose = function () {
console.info('websocket closed! url: ' + url);
rejectInternal();
};
websocket.onerror = function () {
console.info('websocket error! url: ' + url);
rejectInternal();
};
} else {
resolve(existingWebsocket);
}
function rejectInternal() {
if(numberOfRetries <= 0) {
reject();
} else if(!hasReturned) {
hasReturned = true;
console.info('retrying connection to websocket! url: ' + url + ', remaining retries: ' + (numberOfRetries-1));
initWebsocket(url, null, timeoutMs, numberOfRetries-1).then(resolve, reject);
}
}
});
promise.then(function () {hasReturned = true;}, function () {hasReturned = true;});
return promise;
};
/*
var ws_host_fluval = "fluvaledge.local";
var ws_port_fluval = "81";
var ws_server_fluval = "";
var ws_url_fluval = "ws://" + ws_host_fluval + ":" + ws_port_fluval + "/" + ws_server_fluval;
try
{
var socket_fluval = new WebSocket(ws_url_fluval);
// Handlerfunktionen definieren
socket_fluval.onopen = function()
{
// Willkommensnachricht an den Server senden
socket_fluval.send("Client hat Verbindung mit fluvaledge hergestellt");
};
socket_fluval.onmessage = function(msg)
{
console.log("Websocket: " + msg.data);
};
socket_fluval.onclose = function(msg)
{
console.log("Verbindung wurde getrennt");
};
}
catch(ex)
{
alert("Exception: " + ex);
}
*/
答案 0 :(得分:1)
我认为您正在将普通套接字与WebSockets混淆。看着the documentation,看来您不应该使用IoServer
,而应该使用WsServer
。第一种似乎实现了普通套接字,而第二种似乎实现了您尝试从Javascript访问的WebSockets协议。