ARTICLE AD BOX
I have an HTML / JavaScript chat web app using WebSockets. I have also built a simple Ubuntu Linux / Apache2 / PHP socket server geared for WebSockets, using vanilla PHP without third-party libraries. I am using the Apache2 module 'proxy_wstunnel' to pass WebSocket traffic to my server. I cannot use anything but standard PHP on the server side (meaning, I am unwilling to user third-party extensions or libraries due to security concerns).
WebSocket is set up like this:
let ws = null; // [...] // set up websocket stuff ws = new WebSocket('wss://redacted.com/ws/');Typical text frame is sent like this:
let jOut = {act: 'u', typ: '+', usr: uname, grp: gname, tstamp: nowTimestamp()}; ws.send(JSON.stringify(jOut));When the PHP socket server is running, I can successfully connect with the web app, I can send text frames without issue. When done, I call the following to close the WebSocket:
console.log('At ws.close()'); if (ws.readyState === WebSocket.OPEN) { console.log('WebSocket is open, attempting to close'); ws.close(); } else { console.log('WebSocket isn\'t open, not closing'); }'At ws.close()' is shown on the console, but nothing after it. After about ten seconds, I then get a WebSocket error on the console (without any useful information) and also a notice that the WebSocket closed uncleanly with the code 1006.
When viewing the developer tools in Firefox, Safari and Brave, the text frames (opcode 0x1) are shown successfully sending, but I never see the close frame (opcode 0x8) being sent.
On the server side, for debugging, I am running my PHP socket server on the command line. I have set up a few debug outputs to stdout, and I only see opcode 0x1 being received from the web app chat clients (running in Firefox, Safari or Brave). I never see the close frame (0x8) or any other opcode.
The PHP socket server is set up like this:
// create socket server $server = stream_socket_server("tcp://127.0.0.1:8088", $errno, $errstr);I'm using this to wait for client data:
$read = $clients; // copy $clients[] to $read[][ $read[] = $server; // add $server to $read[] $except = null; // unused but variable needed for stream_select $write = null; // unused but variable needed for stream_select // wait for a stream to have data or time out after 200 ms if (stream_select($read, $write, $except, 0, 200000)) { // [...] }Here is the client socket read and debugging lines on the PHP socket server:
// this is a client, so read their data $data = fread($sock, 8192); if ($data === '') { // nothing available right now, but not EOF continue; } if ($data !== '' && $data !== false) { fwrite(STDOUT, "Received frame: " . bin2hex($data) . "\n"); // Full frame in hex fwrite(STDOUT, "Received hex opcode: " . dechex(ord($data[0]) & 15) . "\n"); }When the web app client has logged in, and after the WebSocket handshake happens, the web client sends a few text frames to the server. These text frames are successfully passed on to other connected clients (code not shown). After that, I try ws.close() on the web client, but only get the following debug output:
Received frame: 81cad2260131a90460[...] Received hex opcode: 1 Received frame: 81da632b9f561809fe[...] Received hex opcode: 1 Received frame: 81ca90cdaafdebefcb[...] Received hex opcode: 1Opcode 0x8 is never seen, and the web client times out and outputs the previously-mentioned error and close code 1006.
I have gone round and round with two different AI engines on this and it was unproductive. I'm wondering if anyone has any idea why ws.close() isn't executing on the web clients, why they aren't sending the close frame to the server while text frames work just fine (doesn't seem to be a network issue).
