What does it mean, when an in-browser websocket object receives a onmessage event with the message data length equal to 0?
specifically I use Safari as websocket client (Hixie). The client code is nothing special.
socket = new WebSocket(host);
socket.onmessage = function(msg)
{
log("Received: "+msg.data.length);
if(msg.data.length > 0) ... processing
};
The server is based on PHP, and messages are sent without errors.
I think this is just a Safari annoyance. The current released versions of Safari implement the older WebSockets protocol version and the implementation works but it is a bit lacking. The 0 length messages issue is pretty tame. A more serious issue is the inability to properly close a connection (basically doesn't close the actual socket until the page is reloaded).
Try the same test with a recent Chrome. If you don't see the problem there then it's just a Safari issue. If you still see 0 length messages, then it is likely that the PHP websocket server is sending 0 length messages (perhaps as a sort of poor man keep-alive).
Related
I was asked me to make an api call using websocket with php Ratchet at work. Since I'm totally unfamilier with websocket so I googled and watched youtube videos to solve this problem, but The more I searched, the more I felt it is impossible to call api with websocket.
Am I missing something or is it really impossible to call api by websocket?
If it is possible, can you please show me an example how to do it
I know i might sound awkward since I don't have a solid understanding of websockets, English isn't even my first language, but i'm really desperate please help me
A REST API is fundamentally different from a WebSocket API.
REST API
Calls are made through HTTP(S). You can use AJAX (see here: https://en.wikipedia.org/wiki/Ajax_(programming)) to access HTTP endpoints directly from the browser. In JavaScript you would use the Fetch-API (see here: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) to make calls. Each and every call is stateless per definition. Cookies and special headers must be send with every request to create a context (e.g. user that is logged in).
Example (Client):
fetch('http://example.com/my-rest-api/endpoint1')
.then(response => response.json())
.then(data => console.log(data));
Example (Server):
app.get('/my-rest-api/endpoint1', handlerFunc);
WebSocket API
A stateful connection must be established between a client and a server. The client and server can exchange messages via the connection. Unlike a REST-API messages can be send bidirectional.
A high-level implementation of the WebSocket API is Socket.io.
An API can be designed by defining message types with payloads.
I also would not recommend to use PHP for a WS-API (even though there is a solution like Ratchet). Use a language/runtime that was developed for event-based use cases like this (e.g. nodeJS).
Example (Client):
const socket = SocketClass('example.com/my-websocket-api');
// variant 1 with callbacks
const response = socket.sendMessage('endpoint1', myData);
// variant 2 with message listener
socket.on('endpoint1Response', handlerFunc);
socket.sendMessage('endpoint1', myData);
Example (Server):
const serverSocket = SocketClass('/my-websocket-api');
serverSocket.on('connection', function (socket) {
// variant 1 with callbacks
socket.on('endpoint1', (data, callback) => {
callback(null, responseData);
});
// variant 2 with message listener
socket.on('endpoint1', (data, cb) => {
socket.emit('endpoint1Answer', responseData);
});
});
I want to subscribe the Spring framework WebSocket and receive the reply.
According to my target WebSocket server, the communication is done using STOMP publish protocol (Build based on Java Springframework API) https://stomp.github.io/stomp-specification-1.1.html
Now the client that I am working on, is build based on PHP and using https://github.com/Textalk/websocket-php/ for websocket client.
My idea to receive the server response is to follow the STOMP over Websocket technique based on this guy's answer Websocket Client not receiving any messages.
Using the current websocket client, I perform these steps
Send Connection (request?)
Send Subscription
Actively receive the reply
$client = new WebSocket\Client($ws_url);
//Step 1 Inintate connection;
$open_msg = "CONNECT\naccept-version:1.0,1.1,2.0\n\n\x00\n";
//Step 2 Subscribe Request;
$client->send($open_msg);
$subs = "SUBSCRIBE\nid:0\ndestination:/user/queue\nack:auto\n\n\x00\n";
$client->send($subs);
while (true) {
try {
$message = $client->receive();
echo $message;
// Act[enter image description here][4] on received message
// Later, Break while loop to stop listening
} catch (\WebSocket\ConnectionException $e) {
// Possibly log errors
}
}
$client->close();
The connection (Step 1) is done and tested.
current send and receive result image
Since it is running on the loop, the Received is always printed.
Does anyone know why the API did not send reply?
It turns out, I have to implement the other Websocket library instead
Instead of using https://github.com/Textalk/websocket-php/ , I moved on and use https://github.com/ratchetphp/Pawl
I don't know what just happened. But I think Textalk is synchronous websocket library and ratchet is asynchronous websocket library.
My current hypothesis is whenever you want to do Stomp over websocket, make sure
Send Connection message ("CONNECT\naccept-version:1.0,1.1,2.0\n\n\x00\n")
Send subscription ("SUBSCRIBE\nid:0\ndestination:/user/queue\nack:auto\n\n\x00\n")
Use the asynchronous Websocket instead of synchronous one
Have a nice day
I have a client which GETs a JSON response from a server. I want to calculate how many requests/responses will consume my allotted transfer allowance from a web hosting company (e.g. 100GB per month).
How do I measure/calculate this?
I assume I only need to measure once because the msgs are of a consistent length and format.
I have control over client/server/network. All can be uniquely dedicated to the task. The client is an IOS App and the server is a PHP REST Web Service (on Windows). Both on my LAN.
I know nothing about this and so far have just got the size of the JSON using strlen(). Is that even heading in the right direction?
I would recommend using Charles Proxy. It is an invaluable tool for debugging all kinds of information exchanged via HTTP. You may use it for tracing all HTTP/s communication from and to your iPhone/iPod/iPad as well as the simulator.
It does unfortunately not work too well with most Android devices as those do not really support configuring a system-wide HTTP proxy. For those cases and non HTTP-based communication, I would recommend using WireShark.
In some rare cases, for reasons that are still unclear to me, Charles rarely fails on iOS devices for HTTP-based connections - a typical case would be GoogleAnalytics. For those, again I would recommend WireShark.
The length of JSON string gives you only the size of the payload field in the transferred network packets. This data field may be encapsulated within an HTTP packet and HTTP packet should be put into an IP packet before transmission. Each of these packets have header fields which contributes to total transmission length.
So, for a precise estimate you should first find the real length of the response packet by using Wireshark or an equivalent tool. If this is the only request type for your application you can divide your bandwidth to the response size of your server application to get maximum number of requests to reach the limit. However, this is usually not the case if you have a web application which has several web pages that are accessible from clients, since any access (browsing) will cause a data transfer from server to client.
Your Apache logs will have the number of bytes of each request, but assuming you want a completely PHP solution, add this to the beginning of your scripts:
<?php
function log_input() {
# get raw post data
$length = strlen(file_get_contents('php://input'));
if (function_exists('apache_request_headers')) {
# quick, but not accurate
$length += strlen(serialize(apache_request_headers()));
} else {
# add fudge for HTTP/1.1 etc
$length += strlen($_SERVER['QUERY_STRING']) + 14;
foreach ($_SERVER as $k => $v) {
if (preg_match('/^HTTP/i', $k)) {
$length += strlen($k) + strlen($v);
}
}
}
$s = sprintf("%s\t%s\n", date('c'), $length);
file_put_contents('/tmp/input.log', $s, FILE_APPEND);
}
function log_output() {
$s = sprintf("%s\t%s\n", date('c'), ob_get_length());
file_put_contents('/tmp/output.log', $s, FILE_APPEND);
}
log_input();
register_shutdown_function('log_output');
ob_start();
?>
<html> ....
I'm trying to develop a webchat with HTML5 websocket (with hybi-17 protocol) but I've some problems with chars decoding.
This is what I send through the client (user-agent: Firefox 7):
var socket = new MozWebSocket ('ws://localhost/server.php');
socket.onopen = function () {
alert ('Opened!');
}
Then, I send these data:
socket.send ('Hello');
socket.send ('World');
And this is the server-side code:
$bytes = #socket_recv ($socket, $buffer, BUFSIZE, 0);
if (($bytes == 0) || ($bytes == 2)) {
this->disconnect ($socket);
}
else {
echo $buffer;
}
While this is the data recevied echoed:
��6S~g?Y (Hello)
���~����� (World)
As you can see, the socket is opened and data travels from the client to the server.
The server works with PHP5 and uses normal socket functions to build the connection.
How can I decode that unreadable string in a human readable one?
Thanks in advance.
You have made one of the most common errors people make when they first start writing code that uses TCP -- you forgot to implement the protocol!
In your case, you forgot it in the server. The client already has a WebSocket implementation, and you request it by creating a 'MozWebSocket' object. The WebSocket specification says, "Each frame starts with a 0x00 byte, ends with a 0xFF byte, and contains UTF-8 data in between." Where's the code in the server to find the start of a frame and the end of a frame? Where the code to discard the 0xFF byte?
You actually have to implement the protocol. The protocol specification tells you how to decode the received data. (In your case, the data you are seeing as junk is most likely part of the protocol handshake -- the part that looks like ^n:ds[4U in this description of the handkshake phase.)
I'm pretty sure your method of invoking a PHP script to handle the WebSocket call through the web server will not work. That is, unless your web server knows how to do this -- WaterSpout and phpdaemon do.
Using the base server.php and client.html from http://code.google.com/p/phpwebsocket/ along with modification from HTML5 WebSocket with hybi-17 to deal with the single key standard I can successfully send one message to the server before it closes unexpectedly. It's at least a step closer just not sure as of yet why it closes after one successful message.
I have a web service written in PHP to which an iPhone app connects to. When the app calls the service, a series of notification messages are sent to Apple's APNs server so it can then send Push Notifications to other users of the app.
This process can be time consuming in some cases and my app has to wait a long time before getting a response. The response is totally independent of the result of the notification messages being sent to the APNs server.
Therefore, I would like the web service to send the response back to the app regardless of whether the messages to APNs have been sent.
I tried using pcntl_fork to solve the problem:
<?php
...
$pid = pcntl_fork();
if($pid == -1)
{
// Could not fork (send response anyway)
echo "response";
}
else if($pid)
{
// Parent process - send response to app
echo "response";
}
else
{
// Child process - send messages to APNs then die
sendMessageAPNs($token_array);
die();
}
?> // end of script
Unfortunately, the parent process seems to wait for the child process to end before sending the response even though I do not use pcntl_wait in the parent process. Am I doing something wrong or is this normal behaviour? If this is normal then is there another way I can solve this problem?
Thank you!
If you're hosting the PHP process in Apache then you really shouldn't use this: see this for the section that says *Process Control should not be enabled within a web server environment and unexpected results may happen if any Process Control functions are used within a web server environment. *.
You should probably set up a separate daemon in your preferred language of choice and hand the APNS communication tasks off to that. If you really really really must try using ob_flush().
I think you can send the response back before doing the "long" process. Take a look at the flush() function of PHP it'll maybe help