swoole / swoole-src

🚀 Coroutine-based concurrency library for PHP
https://www.swoole.com
Apache License 2.0
18.42k stars 3.16k forks source link

Client side cannot connect to Swoole websocket #4312

Closed nicktoot closed 3 years ago

nicktoot commented 3 years ago
  1. What did you do? If possible, provide a simple script for reproducing the error.

I installed Swoole on the server using this command: pecl install swoole. Included support for this extension in php.ini for cli. Then I made a file for the websocket and a file for the client side.

Websocket file:

<?php
$server = new swoole_websocket_server('0.0.0.0', 9502);

$server->on('start', function($server) {
  echo "Swoole WebSocket Server started at 0.0.0.0:9502\n";
});

$server->on('open', function($server, $req) {
  echo "connection open: {$req->fd}\n";
});

$server->on('message', function($server, $frame) {
  echo "received message: {$frame->data}\n";
  $server->push($frame->fd, json_encode(["hello", "world"]));
});

$server->on('close', function($server, $fd) {
  echo "connection close: {$fd}\n";
});

echo "Starting...\n";
$server->start();

JavaScript file:

  var wsServer = 'wss://server_ip_address_or_domain:9502';
  var websocket = new WebSocket(wsServer); 
  websocket.onopen = function (evt) { 
    console.log("Connected to WebSocket server.");
  }; 
  websocket.onclose = function (evt) { 
    console.log("Disconnected"); 
  }; 
  websocket.onmessage = function (evt) { 
    console.log('Retrieved data from server: ' + evt.data); 
  }; 
  websocket.onerror = function (evt, e) {
    console.log('Error occured: ' + evt.data);
  };

*in server_ip_address_or_domain I tried to substitute the ip address of my server and the domain of the site

To get started with the websocket server, I run the file with the websocket in the server terminal: php websocket.php

After that, the following messages appear in the terminal (echo from the websocket.php file):

Starting...
Swoole WebSocket Server started at 0.0.0.0:9502

To test the connection on the client side, I opened a page with JS code for a websocket connection. In the network tab, the connection got the status "Pending", after 65-70 seconds it changed to "Finished" and the following messages appeared in the console:

WebSocket connection to 'wss://server_ip_address_or_domain:9502/' failed
Error occured: undefined
Disconnected

During the check using the service https://www.websocket.org/echo.html, everything was the same.

  1. What did you expect to see? I was waiting for a connection between the client and the websocket to continue the integration.

  2. What did you see instead? Instead, I saw a long connection process and a browser error at the end.

  3. What version of Swoole are you using (show your php --ri swoole)?

    
    swoole

Swoole => enabled Author => Swoole Team team@swoole.com Version => 4.6.7 Built => Jul 9 2021 10:36:05 coroutine => enabled with boost asm context epoll => enabled eventfd => enabled signalfd => enabled cpu_affinity => enabled spinlock => enabled rwlock => enabled openssl => OpenSSL 1.1.1f 31 Mar 2020 dtls => enabled pcre => enabled zlib => 1.2.11 mutex_timedlock => enabled pthread_barrier => enabled futex => enabled async_redis => enabled

Directive => Local Value => Master Value swoole.enable_coroutine => On => On swoole.enable_library => On => On swoole.enable_preemptive_scheduler => Off => Off swoole.display_errors => On => On swoole.use_shortname => On => On swoole.unixsock_buffer_size => 8388608 => 8388608


5. What is your machine environment used (show your `uname -a` & `php -v` & `gcc -v`) ?

Linux kfw-engine 5.4.0-51-generic #56-Ubuntu SMP Mon Oct 5 14:28:49 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

PHP 7.4.16 (cli) (built: Mar 5 2021 07:54:38) ( NTS ) Copyright (c) The PHP Group Zend Engine v3.4.0, Copyright (c) Zend Technologies with Zend OPcache v7.4.16, Copyright (c), by Zend Technologies

Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/9/lto-wrapper OFFLOAD_TARGET_NAMES=nvptx-none:hsa OFFLOAD_TARGET_DEFAULT=1 Target: x86_64-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Ubuntu 9.3.0-17ubuntu1~20.04' --with-bugurl=file:///usr/share/doc/gcc-9/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++,gm2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-9 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-9-HskZEa/gcc-9-9.3.0/debian/tmp-nvptx/usr,hsa --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu Thread model: posix gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04)



---------------------

I think that the problem may be in these reasons:
1. Since the connection does not occur, perhaps I am specifying the wrong connection address, but then what address is needed if the ip / site domain + websocket port does not work?
2. Since the response comes in 65-70 seconds, this may indicate that php is trying to process the request and in a minute it finishes processing (max_execution_time = 60). But I am not getting any errors in the terminal.
3. I have incorrectly configured the websocket in the php file, and I need to add something else to it, but in all the basic examples there is about the same setting

Many thanks in advance to everyone for your attention and for any advice that will help me.
sy-records commented 3 years ago

You may need to use ws://127.0.0.1:9502

matyhtf commented 3 years ago

Your server should enable SSL encryption.

$server = new Swoole\WebSocket\Server('0.0.0.0', 9501, SWOOLE_PROCESS, SWOOLE_SOCK_TCP | SWOOLE_SSL);
$server->set(array(
    'ssl_cert_file' => __DIR__.'/ssl.cert',
    'ssl_key_file' => __DIR__.'/ssl.key',
));
nicktoot commented 3 years ago
  1. @sy-records Unfortunately, I cannot use ws instead of wss, because in this case the browser immediately reports an error, because the SSL certificate (https) is installed on the server.
  2. @matyhtf Changing the file did not affect the work in any way, the connection is also not established. I already tried this before you wrote about it, my code is:
    
    <?php
    $server = new swoole_websocket_server('0.0.0.0', 9502, SWOOLE_PROCESS, SWOOLE_SOCK_TCP | SWOOLE_SSL);
    $server->set([
    'ssl_cert_file' => '/etc/nginx/ssl/example-domain.com/1054227/server.crt',
    'ssl_key_file' => '/etc/nginx/ssl/example-domain.com/1054227/server.key',
    ]);

$server->on('start', function($server) { echo "Swoole WebSocket Server started at 0.0.0.0:9502\n"; });

$server->on('open', function($server, $req) { echo "connection open: {$req->fd}\n"; });

$server->on('message', function($server, $frame) { echo "received message: {$frame->data}\n"; $server->push($frame->fd, json_encode(["hello", "world"])); });

$server->on('close', function($server, $fd) { echo "connection close: {$fd}\n"; });

echo "Starting...\n"; $server->start();


It seems to me that the whole thing is about SSL, maybe there are some problems with my server on Laravel Forge and connections via wss on a custom port. Do you have any information on this? I found some article: https://alex.bouma.blog/posts/installing-laravel-websockets-on-forge-with-ssl/ But not sure if this is my case.
nicktoot commented 3 years ago

I found a solution to my problem. The problem was that for the nginx server, it was necessary to add a new rule inside the server section so that the server could normally process the request to the websocket:

server {
  #other rules above

  location /ws {
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    proxy_set_header Proxy "";
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_pass http://localhost:9502;
  }

  #other rules below
}

After that be sure to reload nginx on your server:

sudo systemctl reload nginx

The websocket settings (php file) remained as in the uppermost example (without adding the paths to the ssl certificate), only the connection link in JavaScript changed to:

var websocket = new WebSocket ('wss://site-domain.com/ws');