Working with WebSocket

itzmeanjan

Anjan Roy

Posted on April 26, 2019

Working with WebSocket

init

WebSocket -- used in real-time data transfer scenarios, such as multiplayer games/ chatbots/ sensor network in IoT etc.

define

Well, WebSocket is simply a general HTTP connection with some modifications, where a normal HTTP connection gets upgraded to WebSocket connection, when two communicating PEERs agree to use a single socket for all their communication, followed by a handshake. It could be thought of as a bidirectional communication channel in between two PEERs. When communication ends, that socket is destroyed.

idea

May be you've already worked with WebSocket using NodeJS or Java or PHP or Python or something else, but today we're going to use Dart Language for implementing both WebSocket Server & Client in a much easier way.

Alright so let's get into coding ...

implement

First we're going to write a WebSocket Server

WebSocket Server

As I've already said, WebSocket is a modified version of a HTTP connection, we're going to create a HttpServer and then we'll upgrade that connection to WebSocket.

import 'dart:io' show HttpServer, HttpRequest;
main() {
  HttpServer.bind('localhost', 8000).then((HttpServer server) {
      // httpserver listens on http://localhost:8000
    print('[+]HttpServer listening at -- http://localhost:8000');
    server.listen((HttpRequest request) {

       // more code goes here

    }, onError: (err) => print('[!]Error -- ${err.toString()}'));
  }, onError: (err) => print('[!]Error -- ${err.toString()}'));
}
Enter fullscreen mode Exit fullscreen mode

Now we've HttpRequest object, which is going to be upgraded to WebSocket.

import 'dart:io' show WebSocket, WebSocketTransformer;
import 'dart:convert' show json;
import 'dart:async' show Timer;
// will put this snippet with in main()
WebSocketTransformer.upgrade(request).then((WebSocket ws) {
    // upgradation happens here and now we've a WebSocket object
        ws.listen( // listening for data
          (data) {
            print(
                '\t\t${request?.connectionInfo?.remoteAddress} -- ${Map<String, String>.from(json.decode(data))}'); // client will send JSON data
            Timer(Duration(seconds: 1), () {
              if (ws.readyState == WebSocket.open)
                ws.add(json.encode({
                  'data': 'from server at ${DateTime.now().toString()}', // in response JSON data is sent back to client
                })); // Timer helps to schedule code execution
            });
          },
          onDone: () => print('[+]Done :)'),
          onError: (err) => print('[!]Error -- ${err.toString()}'),
          cancelOnError: true,
        );
      }, onError: (err) => print('[!]Error -- ${err.toString()}'));
Enter fullscreen mode Exit fullscreen mode

See it's this much easy to upgrade a HTTP connection to WebSocket connection, with Dart ❤️.

Here's our whole WebSocket Server code.

import 'dart:io' show HttpServer, HttpRequest, WebSocket, WebSocketTransformer;
import 'dart:convert' show json;
import 'dart:async' show Timer;

main() {
  HttpServer.bind('localhost', 8000).then((HttpServer server) {
    print('[+]WebSocket listening at -- ws://localhost:8000/');
    server.listen((HttpRequest request) {
      WebSocketTransformer.upgrade(request).then((WebSocket ws) {
        ws.listen(
          (data) {
            print(
                '\t\t${request?.connectionInfo?.remoteAddress} -- ${Map<String, String>.from(json.decode(data))}');
            Timer(Duration(seconds: 1), () {
              if (ws.readyState == WebSocket.open)
              // checking connection state helps to avoid unprecedented errors
                ws.add(json.encode({
                  'data': 'from server at ${DateTime.now().toString()}',
                }));
            });
          },
          onDone: () => print('[+]Done :)'),
          onError: (err) => print('[!]Error -- ${err.toString()}'),
          cancelOnError: true,
        );
      }, onError: (err) => print('[!]Error -- ${err.toString()}'));
    }, onError: (err) => print('[!]Error -- ${err.toString()}'));
  }, onError: (err) => print('[!]Error -- ${err.toString()}'));
}
Enter fullscreen mode Exit fullscreen mode

Let's go for WebSocket Client.

WebSocket Client

Now Dart has got a class WebSocket in dart:io, which takes care of implementation of WebSocket Client, does all the heavy liftings for us ⚒️.

You can assume, implementation of WebSocket Client will be much easier.

import 'dart:io' show WebSocket;
import 'dart:convert' show json;
import 'dart:async' show Timer;

main() {
  WebSocket.connect('ws://localhost:8000').then((WebSocket ws) {
      // our websocket server runs on ws://localhost:8000
    if (ws?.readyState == WebSocket.open) {
        // as soon as websocket is connected and ready for use, we can start talking to other end
      ws.add(json.encode({
        'data': 'from client at ${DateTime.now().toString()}',
      })); // this is the JSON data format to be transmitted
      ws.listen( // gives a StreamSubscription
        (data) {
          print('\t\t -- ${Map<String, String>.from(json.decode(data))}'); // listen for incoming data and show when it arrives
          Timer(Duration(seconds: 1), () {
            if (ws.readyState == WebSocket.open) // checking whether connection is open or not, is required before writing anything on socket
              ws.add(json.encode({
                'data': 'from client at ${DateTime.now().toString()}',
              }));
          });
        },
        onDone: () => print('[+]Done :)'),
        onError: (err) => print('[!]Error -- ${err.toString()}'),
        cancelOnError: true,
      );
    } else
      print('[!]Connection Denied');
      // in case, if serer is not running now
  }, onError: (err) => print('[!]Error -- ${err.toString()}'));
}

Enter fullscreen mode Exit fullscreen mode

Wasn't it easier than WebSocket Server implementation ?

And yes, with 930 bytes of client-side Dart code and 1175 bytes of server-side Dart code, we've completed WebSocket implementation.

run

Make sure you've installed Dart SDK from here and set PATH variable properly.

Time to run these beasts 😆

$ dart websocket_server.dart
Enter fullscreen mode Exit fullscreen mode

And in another terminal

$ dart websocket_client.dart
Enter fullscreen mode Exit fullscreen mode

And 💥

websocket client-server on run

end

In this article, you've learnt how to use Dart for building WebSocket Peers, for tranferring real-time data.

Got any problems ?

Yes

Find me on Twitter

Wrap up time. See you in next article.

In the mean time, you may check out my GitHub profile for my other projects.

💖 💪 🙅 🚩
itzmeanjan
Anjan Roy

Posted on April 26, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Working with WebSocket
javascript Working with WebSocket

April 26, 2019