It really depends on your needs. I'm mostly used to the server side of things writing cyclic executives, so i'm not sure what event based options for clients are available ;-)
The couple of times i needed a websocket client, i did it "by hand" using Protocol::WebSocket::Frame after connecting via IO::Socket::SSL, because that works well enough for my own cyclic needs.
Connection is easy, unless the W3C has re-defined things yet again. Here's an untested(!) minimal cyclic executive (a "worker") based on some of my existing codebase. I didn't include all that much error handling here, though, to keep the code small.
use IO::Socket::SSL;
use Protocol::WebSocket::Frame;
use Carp;
use Time::HiRes qw(sleep);
use Data::Dumper;
# Connect to server
my $sock = IO::Socket::SSL->new(
PeerHost => $self->{server},
PeerPort => $self->{port},
SSL_verify_mode => SSL_VERIFY_NONE,
) or croak($!);
binmode($sock);
# Switch to unblocking after the SSL initiation
$sock->blocking(0);
# Write the header
my $header =
"GET /public/api/blablabla HTTP/1.1\r\n" .
"Host: example.com\r\n" .
"Upgrade: websocket\r\n" .
"Connection: Upgrade\r\n" .
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" .
"Sec-WebSocket-Protocol: chat\r\n" .
"Sec-WebSocket-Version: 13\r\n" .
"Origin: https://cavac.at\r\n" .
"\r\n";
$syswrite($sock, $header);
# "Parse" the return headers from the server by just skipping over it,
+ hoping for the best ;-)
syswrite($sock, $header);
my $line = "";
while(1) {
my $char;
sysread($sock, $char, 1);
if(defined($char) && length($char)) {
if($char eq "\r") {
next;
} elsif($char eq "\n") {
if($line eq "") {
# end of header
last;
} else {
$line = "";
}
} else {
$line .= $char;
}
} else {
sleep(0.05); # wait a few microseconds for more data
}
}
# Initiate the websocket frame handler
my $frame = Protocol::WebSocket::Frame->new(max_payload_size => 500 *
+1024 * 1024, masked => 1);
# Send a frame
{
my %request = (
'request-type' => 'HelloWorld',
'message-id' => 'rand' . int(rand(1_000_000)),
'other-stuff' => 'Hello Welt!',
);
my $outframe = $frame->new(buffer => encode_json(\%request), type
+=> 'text', masked => 1)->to_bytes;
syswrite($sock, $outframe);
}
# Handle messages from server
while(1) {
# Read from socket and append data to the frame parser
my $workCount = 0;
while(1) {
my $char;
sysread($sock, $data, 1_000);
last if(!defined($data) || !length($data));
$frame->append($data);
$workCount++;
}
# Parse and react to messages from server
while(my $data = $frame->next_bytes) {
my $msg = decode_json($data);
print Dumper($msg); # Just print it out
}
if(1) { # Other cyclic work you need to do in the program
# doSomeStuff();
# $workCount++;
}
if(!$workCount) {
# Nothing happened, just sleep a bit, try again later. Save on
+ CPU cycles
sleep(0.05);
}
}
Hope that helps.