I'm learning WebSocket using PHP library Ratchet. But I have a problem sending the message from client/browser. I have tried using chrome and firefox.
The message is not sent to the server until I disconnect the client by closing the tab or refresh the browser.
Update: My server use Centos 7 with firewalld enabled.
After I close the browser tab, the server output is like this:
Connection 73 sending message "tes" to 1 other connection
Connection 73 has disconnected
Here is the javascript code:
conn = new WebSocket('ws://websocket.develop.local:8080');
conn.onopen = function(e) {
console.log("Connection established!");
};
conn.onmessage = function(e) {
console.log('ada message');
console.log(e.data);
};
conn.onerror = function(e) {
console.log("WebSocket Error: " , e);
//Custom function for handling errors
//handleErrors(e);
};
function sendMessage(){
var message = document.getElementById("pesan").value;
conn.send(message);
console.log('Sending message: ' + message);
};
And here is the PHP code (I got this from Ratchet docs):
<?php
namespace MyApp;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
class Chat 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();
}
}
Related
I'm new with websocket things. I tried to make a simple chat application, and i've followed ratchet hello world tutorial. I ran it locally with
'ws://localhost:8080'
It's works perfectly fine. I can chat via javascript console like the tutorials said. Now, i try to put it on my webserver https://some.domain.co/websocket. I've tried to do the same thing like
'ws://some.domain.co:8080'
'ws://some.domain.co:8080/websocket'
'ws://some.domain.co/websocket:8080'
'wss://some.domain.co:8080'
'wss://some.domain.co:8080/websocket'
'wss://some.domain.co/websocket:8080'
But none of them work. By browser still give error
WebSocket connection to 'wss://some.domain.co/' failed: Error during
WebSocket handshake: Unexpected response code: 200
or
WebSocket connection to 'wss://some.domain.co:8080/' failed: Error in connection establishment: net::ERR_TIMED_OUT
I think i had something wrong with my url. Any advice? Thanks before
Edit
chatServer.php
require dirname(__DIR__) . '/vendor/autoload.php';
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
include("Chat.php");
require dirname(__DIR__) . '/vendor/autoload.php';
$server = IoServer::factory(
new HttpServer(
new WsServer(
new Chat()
)
), 8080
);
$server->run();
Chat.php
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
class Chat implements MessageComponentInterface {
protected $clients;
public function __construct() {
$this->clients = new \SplObjectStorage;
echo "Server is Running\n";
}
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) {
$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();
}
}
I'm trying to make a chat using WebSocket. In that purpose I use Ratchet.
For that, I'm using the guide from Ratchet :
http://socketo.me/docs/hello-world
My problem is that after sending a message, the page reloads without any implementation of code for it.
index.html :
<html> <!-- index.html -->
<head>
</head>
<body>
<h1>Menu</h1>
<h2>Create a chat server on port 8080</h2>
<button>Here</button>
<hr>
<h2>Join the chat server on port 8080</h2>
<button>Here</button>
<p>You'll have an error if it doesn't exist !</p>
</body>
</html>
connection.js:
var conn;
function init(){
console.log("function : init");
conn = new WebSocket('ws://localhost:8080');
console.log(conn);
conn.onopen = function(e) {
var co = document.getElementById("connection");
co.innerHTML="Connection established !";
};
conn.onmessage = function(e) {
var content = document.getElementById("chat");
content.innerHTML = content.innerHTML + "<li>"+ e.data+"</li>";
};
conn.onclose = function(){
var co = document.getElementById("connection");
co.innerHTML="Connection closed !";
}
conn.onerror = function(){
alert("Connection failed : There in no server on this port !");
}
}
function closeCon(){
conn.close();
}
function sendMessage(){
var mes = document.getElementById("message").value;
conn.send(mes, function(event){
event.preventDefault();
console.log(event);
} );
}
chat-client.php :
<html><!-- chat-client.php -->
<head>
<script src="../js/connection.js"></script>
</head>
<body onload="init()">
<h1>Chat in web browser</h1>
<p id="connection"> Connection closed !</p>
<div>
<ul id="chat">
</ul>
<form>
<input id="message" style="border: 1;">
<button onclick="sendMessage()">Send</button>
</form>
</div>
<hr>
<button onclick="closeCon()">Back to the menu</button>
</body>
</html>
chat-server.php :
<h1>Welcome on your server on port 8080</h1>
<?php
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use MyApp\Chat;
// cd /Applications/MAMP/htdocs/MyRatchetFirstApp/
require dirname(__DIR__) . '/vendor/autoload.php';
$server = IoServer::factory(
new HttpServer(
new WsServer(
new Chat()
)
),
8080
);
$server->run();
Chat.php :
<?php //Chat.php
namespace MyApp;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
class Chat 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})<br/>";
}
public function onMessage(ConnectionInterface $from, $msg) {
$numRecv = count($this->clients) - 1;
foreach ($this->clients as $client) {
if ($from !== $client) {
// The sender is not the receiver, send to each client connected
$client->send($msg);
}
}
echo sprintf('Connection %d sending message "%s" to %d other connection%s' . "<br/>", $from->resourceId, $msg, $numRecv, $numRecv == 1 ? '' : 's');
}
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<br/>";
}
public function onError(ConnectionInterface $conn, \Exception $e) {
echo "An error has occurred: {$e->getMessage()}<br/>";
$conn->close();
}
}
composer.json :
{
"autoload": {
"psr-0": {
"MyApp": "src"
}
},
"require": {
"cboden/ratchet": "0.3.*"
}
}
And finally, here,the tree of this project
That was just the button to send the message was in a form. Then when I "submit" it, it refreshed the page. If you want to have an history of the posts, you should remove this form.
Im kinda new with the sockets stuff and Im trying to make a server on PHP to support websockets calls from my javascript currently my code looks like this
<?php
class Websocket
{
private $server;
private $sockets = [];
public function create($host)
{
$this->server = stream_socket_server('tcp://localhost:8080', $errno, $errmsg);
stream_set_blocking($this->server, 0);
}
public function run()
{
while(true)
{
$client = stream_socket_accept($this->server);
if($client)
{
$data = stream_socket_recvfrom($client, 2048);
if($data)
{
echo 'Client connected'.PHP_EOL;
echo $data;
$response = $this->handshake($data);
stream_socket_sendto($client, $response);
}
}
}
}
private function handshake($data)
{
$data = explode(PHP_EOL, $data);
foreach($data as $header)
{
$current_header = explode(':', $header);
if($current_header[0] == 'Sec-WebSocket-Key')
{
$accept = base64_encode(sha1(trim($current_header[1]).'258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true));
$response = 'HTTP/1.1 101 Switching Protocols'.PHP_EOL.'Upgrade: websocket'.PHP_EOL.'Connection: Upgrade'.PHP_EOL.'Sec-WebSocket-Accept:'.$accept.PHP_EOL.PHP_EOL;
return $response;
}
}
}
}
And my javascript is just a simple
var socket = new WebSocket('ws://localhost:8080');
socket.onopen = function(event)
{
console.log('connected');
socket.send('hello');
}
Currently the message connected appears on my chrome console but after that when the hello message is supposed to be sent I get this error
"connection to: xxx was interrupted while the page was loading"
So my question is after I have successfully send the handshake to the client how do I process messages? I know my code is always sending the handshake to new connections but on my server I will only see the first message beeing echoed (the http request) and not the "hello" one
You need to handle the message -
socket.onmessage = function(e){
var server_message = e.data;
console.log(server_message);
}
I am writing a project that is in 2 parts.
So far I have a front end View.php (HTML5,CSS3,JQuery) and this will query the server.php
The server PHP opens a TCP socket to a server and listens in and can make commands by writing to the socket.
The normal procedure now goes like this
View.php -> Calls using rest API to server.php
Server.php -> Connects to TCP -> Reads from TCP -> Json_encodes & print -> close TCP socket connection.
What I want to achieve is a script Server.php that once started. It constantly listens in to a server, until it gets a shutdown command. I want to keep a fsocket connection open. Any thoughts?
The answer is using non blocking programming. In PHP we have specific function for non blocking I/O. For sockets you should use socket_set_nonblock function on a socket resource.
$port = 8081;
$address = '127.0.0.1';
if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) {
echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n";
exit();
}
if (socket_bind($sock, $address, $port) === false) {
echo "socket_bind() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";
exit();
}
if (socket_listen($sock, 5) === false) {
echo "socket_listen() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";
}
socket_set_nonblock($sock);
echo "listening for new connection".PHP_EOL;
$conneted_clients = [];
do {
$clientsock = socket_accept($sock);
if($clientsock !== false){
socket_set_nonblock($clientsock);
$conneted_clients[] = $clientsock;
socket_getpeername($clientsock,$address);
echo "New Connection from: ".$address.PHP_EOL;
$msg = PHP_EOL."Welcome to the PHP Test Server. " . PHP_EOL.
"To quit, type 'quit'. To shut down the server type 'shutdown'." . PHP_EOL;
socket_write($clientsock, $msg, strlen($msg));
}
$status = check_clients($conneted_clients);
if(!$status) break;
usleep(500000);
} while (true);
function check_clients($clients)
{
foreach($clients as $key => $con)
{
if(get_resource_type($con) !== "Socket")
{
socket_getpeername($clientsock,$address);
echo $address." has diconnected.".PHP_EOL;
unset($clients[$key]);
continue;
}
if (false === $buff = socket_read($con, 2048)) {
continue;
}
$buff = trim($buff);
if ($buff == 'quit') {
socket_close($con);
unset($clients[$key]);
continue;
}
if (trim($buff) == 'shutdown') {
socket_close($con);
echo "shutdown initiated".PHP_EOL;
return FALSE;
}
if($buff != false || $buff != null)
{
$talkback = "PHP: You said '$buff'.".PHP_EOL;
socket_write($con, $talkback, strlen($talkback));
echo "$buff".PHP_EOL;
}
}
return TRUE;
}
echo "Closing Server";
socket_close($sock);
I'm trying to create a simple WebSocket example using the HTML5/JS API. Based on what I trace out on the server, it seems like the socket is connecting, but none of the events fire (onopen, onmessage, onclose, etc). I'm a Flash developer so I'm not very good at debugging the JavaScript and I'm hoping someone can help me out. Here's the client side code I'm using:
<script type="text/javascript" charset="utf-8">
function startSocket()
{
if("WebSocket" in window)
{
var ws = new WebSocket("ws://localhost:1740");
ws.onopen = function() {
window.alert("open!");
}
ws.onmessage = function(event) {
window.alert(event.data);
}
ws.onclose = function() {
window.alert("Closed");
}
ws.onerror = function() {
window.alert("trouble in paradise");
}
}
}
</script>
And here's my socket server code (which works just fine from Flash, but that may not mean anything):
<?php
create_connection('localhost',1740);
function create_connection($host,$port)
{
$socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
if (!is_resource($socket)) {
echo 'Unable to create socket: '. socket_strerror(socket_last_error()) . PHP_EOL;
} else {
echo "Socket created.\n";
}
if (!socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1)) {
echo 'Unable to set option on socket: '. socket_strerror(socket_last_error()) . PHP_EOL;
} else {
echo "Set options on socket.\n";
}
if (!socket_bind($socket, $host, $port)) {
echo 'Unable to bind socket: '. socket_strerror(socket_last_error()) . PHP_EOL;
} else {
echo "Socket bound to port $port.\n";
}
if (!socket_listen($socket,SOMAXCONN)) {
echo 'Unable to listen on socket: ' . socket_strerror(socket_last_error());
} else {
echo "Listening on the socket.\n";
}
while (true)
{
$connection = #socket_accept($socket);
if($connection)
{
echo "Client $connection connected!\n";
send_data($connection);
} else {
echo "Bad connection.";
}
}
}
function send_data($connection)
{
echo $connection;
// Create a number between 30 and 32 that will be our initial stock price.
$stock_price = rand(30,32);
while (true)
{
socket_write($connection,"$stock_price\n",strlen("$stock_price\n"));
sleep(1);
// Generate a random number that will represent how much our stock price
// will change and then make that number a decimal and attach it to the
// previous price.
$stock_offset = rand(-50,50);
$stock_price = $stock_price + ($stock_offset/100);
echo "$stock_price\n";
}
}
?>
Are you calling startSocket() somewhere else in your code?
I know this code works. You might be able to adapt it: http://github.com/dshaw/zombo-socket/blob/master/zombocom-client.html
Maybe this is completely obvious, but if anyone else gets this, the problem is that you need to add a handshake. In Flash this isn't required and I still don't fully understand it, but I was able to modify this project - http://code.google.com/p/phpwebsocket/ - and it worked as it was supposed to by adding the gethandshake code after my socket_accept code ran.