Writing a Delphi WebSocket server and Smart Mobile Client in 15 minutes
Jon L. Aasenden - September 26, 2015
Jon L. Aasenden - September 26, 2015
[SHOWTOGROUPS=4,20]
Websocket is all the rage these days. In essence its just an extra layer built on top of ordinary HTTP (available as a snap-in for IIS and “mod” for apache). But Delphi developers like to build their solutions from the ground up! So what could possibly be better than to roll your own?
Indy to the rescue
No I didnt see you playing with your sockets SIR!
Think of client-server programming and Delphi and chances are “indy” will be the first word to pop into your mind. It’s been there for ages, it’s rock solid, it supports every known RFC known to mankind – and it’s tried and tested by time. It may not provide the same speed as Microsoft Internet Explorer or Apache, but there are hundreds (if not thousands) of products out there built with the Indy library, so it’s pretty damn awesome!
But what about websocket? As far as standards go it’s the new kid on the block – invented more or less purely for secure HTML5/JavaScript development. Does Indy have that yet? Well, no. I’m sure it will be included at one point in a future update, but thankfully Indy is easy to extend and mold due to it’s purely object oriented nature.
A while back mr. Andre Mucche took the time to implement just that, extending an ordinary Indy HTTP server with the required plumbing – turning a bog standard, multi-threaded, multi-context HTTP server into a websocket nerdvana.
Why is this important?
If all you do is write old-school stuff in Delphi then you probably don’t need it, but if you want to keep up with the way technology is moving – then WebSockets is bound (pun intended) to cross your path sooner or later. If you havent already been asked by your customers, it’s only a matter of time before you are approached with the question “Can we poll data from our Delphi solution and use that on our website from JavaScript?”.
Well, there are many ways to deal with getting data from a Delphi centric solution (read: server) onto your website. You can spend weeks and months writing the JavaScript yourself, you can publish a few DataSnap API’s — or go for RemObjects SDK which IMHO is a much better alternative to DataSnap.
But Smart Mobile Studio offers an alternative route. The benefits should be fairly obvious:
The Delphi side
Right, first start by creating a folder for your project. In my example I just named it “WebSocket”. Then create a fresh Delphi project (VCL) and save that into the folder as “SocketServer.dpr”.
Next, download Andre’s WebSocket extension units, these can be found here: Для просмотра ссылки Войдиили Зарегистрируйся. It’s Github so just download the zip archive. Once downloaded, unzip the files into your project folder. Your folder should look something like this by now:
Для просмотра ссылки Войдиили Зарегистрируйся
Quick and dirty
With the files in place, add all the units to your project inside Delphi (including the superobject files). You dont really have to do this, you can unzip the files wherever you like — but for this quick demonstration I just stuff it all into the same project to avoid setting a path (it’s late, what can I say). Your Delphi project should now look like this:
Для просмотра ссылки Войдиили Зарегистрируйся
Easy as apple-pie
With that in place, let’s add a TMemo component, a couple of buttons to control the server (start and stop) and isolate that in TActions. If you havent used actions before then please read up on that before you continue. It’s super simple and one of Delphi’s biggest strength’s over other RAD platforms out there. My form looks like this (just slap-dash 2 second stuff):
Для просмотра ссылки Войдиили Зарегистрируйся
Not much to look at, but bling comes last
Now let’s write some code!
That’s basically it! The most bare-bone WebSocket server you will ever see. It just accepts a connection and dumps whatever text a client writes to the memo control on the form.
Right, now let’s look at the Smart Mobile Studio side of things.
The HTML5 Client
Fire up Smart Mobile Studio (im using the latest beta here) and create a new project. Remember to save the project before you start coding.
We will be adding a single button for connecting to the websocket server, and then a textbox for message input — and finally a “send” button to ship the next to the server.
Для просмотра ссылки Войдиили Зарегистрируйся
This is what my slap-dash client looks like.
With some components in place we move on to the WebSocket client code, which under the Smart Mobile RTL is a piece of cake:
The final result
Now fire up your Delphi project, click the “start” button to initialize the server (note: the firewall may ask you to allow the server to use the port, remember to check “local networks” and just click “ok”). Your Delphi server should now run at port 8080 — use your favorite browser to check that it works. It should return “hello world” (see “HandleCommandGet” event handler in the Delphi code).
Next, fire up your Smart Mobile Studio project. Hit the “Connect” button, type something in the text-field and click “send” to ship it off to the server. Now watch the memo on the server and voila — you have just written your first websocket client/server system in less than 15 minutes!
Для просмотра ссылки Войдиили Зарегистрируйся
Websocket has never been easier!
Note: Remember to use your local IP. The IP listed in the SMS example above is just a local address on my local network. If you are running Delphi and SMS on the same machine, just use 127.0.0.1 and bob’s your uncle.
[/SHOWTOGROUPS]
Websocket is all the rage these days. In essence its just an extra layer built on top of ordinary HTTP (available as a snap-in for IIS and “mod” for apache). But Delphi developers like to build their solutions from the ground up! So what could possibly be better than to roll your own?
Indy to the rescue
No I didnt see you playing with your sockets SIR!
Think of client-server programming and Delphi and chances are “indy” will be the first word to pop into your mind. It’s been there for ages, it’s rock solid, it supports every known RFC known to mankind – and it’s tried and tested by time. It may not provide the same speed as Microsoft Internet Explorer or Apache, but there are hundreds (if not thousands) of products out there built with the Indy library, so it’s pretty damn awesome!
But what about websocket? As far as standards go it’s the new kid on the block – invented more or less purely for secure HTML5/JavaScript development. Does Indy have that yet? Well, no. I’m sure it will be included at one point in a future update, but thankfully Indy is easy to extend and mold due to it’s purely object oriented nature.
A while back mr. Andre Mucche took the time to implement just that, extending an ordinary Indy HTTP server with the required plumbing – turning a bog standard, multi-threaded, multi-context HTTP server into a websocket nerdvana.
Why is this important?
If all you do is write old-school stuff in Delphi then you probably don’t need it, but if you want to keep up with the way technology is moving – then WebSockets is bound (pun intended) to cross your path sooner or later. If you havent already been asked by your customers, it’s only a matter of time before you are approached with the question “Can we poll data from our Delphi solution and use that on our website from JavaScript?”.
Well, there are many ways to deal with getting data from a Delphi centric solution (read: server) onto your website. You can spend weeks and months writing the JavaScript yourself, you can publish a few DataSnap API’s — or go for RemObjects SDK which IMHO is a much better alternative to DataSnap.
But Smart Mobile Studio offers an alternative route. The benefits should be fairly obvious:
- You write object pascal (Delphi / FreePascal)
- You don’t have to learn much JavaScript
- All the low-level stuff is already wrapped and ready
- Smart Mobile supports both RemObjects, DataSnap and Websocket (and a few more)
The Delphi side
Right, first start by creating a folder for your project. In my example I just named it “WebSocket”. Then create a fresh Delphi project (VCL) and save that into the folder as “SocketServer.dpr”.
Next, download Andre’s WebSocket extension units, these can be found here: Для просмотра ссылки Войди
Для просмотра ссылки Войди
Quick and dirty
With the files in place, add all the units to your project inside Delphi (including the superobject files). You dont really have to do this, you can unzip the files wherever you like — but for this quick demonstration I just stuff it all into the same project to avoid setting a path (it’s late, what can I say). Your Delphi project should now look like this:
Для просмотра ссылки Войди
Easy as apple-pie
With that in place, let’s add a TMemo component, a couple of buttons to control the server (start and stop) and isolate that in TActions. If you havent used actions before then please read up on that before you continue. It’s super simple and one of Delphi’s biggest strength’s over other RAD platforms out there. My form looks like this (just slap-dash 2 second stuff):
Для просмотра ссылки Войди
Not much to look at, but bling comes last
Now let’s write some code!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | unit mainform; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, IdComponent, IdContext, IdCustomHTTPServer, IdServerWebsocketContext, IdServerSocketIOHandling, IdWebsocketServer, Vcl.StdCtrls, System.Actions, Vcl.ActnList; type TForm1 = class(TForm) Memo1: TMemo; Button1: TButton; Button2: TButton; ActionList1: TActionList; acStart: TAction; acStop: TAction; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure acStartExecute(Sender: TObject); procedure acStopExecute(Sender: TObject); procedure acStartUpdate(Sender: TObject); procedure acStopUpdate(Sender: TObject); private { Private declarations } FServer: TIdWebsocketServer; procedure HandleServerStatus(ASender: TObject; const AStatus: TIdStatus; const AStatusText: string); procedure HandleTextMessage(const AContext: TIdServerWSContext; const aText: string); procedure HandleCommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo); public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.acStartExecute(Sender: TObject); begin FServer.Active:=True; end; procedure TForm1.acStartUpdate(Sender: TObject); begin TAction(sender).Enabled := not FServer.Active; end; procedure TForm1.acStopExecute(Sender: TObject); begin FServer.Active := false; end; procedure TForm1.acStopUpdate(Sender: TObject); begin TAction(sender).Enabled := FServer.Active; end; procedure TForm1.FormCreate(Sender: TObject); begin FServer := TIdWebsocketServer.Create(NIL); FServer.OnStatus := HandleServerStatus; FServer.OnMessageText := HandleTextMessage; FServer.OnCommandGet := HandleCommandGet; FServer.KeepAlive := True; FServer.DefaultPort := 8080; end; procedure TForm1.FormDestroy(Sender: TObject); begin FServer.free; end; procedure TForm1.HandleCommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo); begin aResponseInfo.ContentText:='Hello world'; end; procedure TForm1.HandleTextMessage(const AContext: TIdServerWSContext; const aText: string); begin memo1.Lines.Add(aText); end; procedure TForm1.HandleServerStatus(ASender: TObject; const AStatus: TIdStatus; const AStatusText: string); begin memo1.Lines.Add(aStatusText); end; end. |
That’s basically it! The most bare-bone WebSocket server you will ever see. It just accepts a connection and dumps whatever text a client writes to the memo control on the form.
Right, now let’s look at the Smart Mobile Studio side of things.
The HTML5 Client
Fire up Smart Mobile Studio (im using the latest beta here) and create a new project. Remember to save the project before you start coding.
We will be adding a single button for connecting to the websocket server, and then a textbox for message input — and finally a “send” button to ship the next to the server.
Для просмотра ссылки Войди
This is what my slap-dash client looks like.
With some components in place we move on to the WebSocket client code, which under the Smart Mobile RTL is a piece of cake:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | unit Form1; interface uses SmartCL.inet, SmartCL.System, SmartCL.Graphics, SmartCL.Components, SmartCL.Forms, SmartCL.Fonts, SmartCL.Borders, SmartCL.Application, SmartCL.Controls.Button, SmartCL.Controls.Memo, SmartCL.Controls.EditBox; type TForm1 = class(TW3Form) procedure W3Button2Click(Sender: TObject); procedure W3Button1Click(Sender: TObject); private {$I 'Form1:intf'} FSocket: TW3WebSocket; protected procedure InitializeForm; override; procedure InitializeObject; override; procedure Resize; override; end; implementation { TForm1 } procedure TForm1.W3Button1Click(Sender: TObject); begin try FSocket.Connect('ws://192.168.10.106:8080',[]); except on e: exception do showmessage(e.message); end; end; procedure TForm1.W3Button2Click(Sender: TObject); var mText:String; begin mText :=trim(w3Editbox1.text); if mtext.length > 0 then FSocket.Write(mText); w3Editbox1.text := ''; end; procedure TForm1.InitializeForm; begin inherited; // this is a good place to initialize components FSocket := TW3WebSocket.Create; FSocket.OnOpen := procedure (sender:TW3WebSocket) begin w3memo1.text := w3memo1.text + "WebSocket open" + #13; end; end; procedure TForm1.InitializeObject; begin inherited; {$I 'Form1:impl'} end; procedure TForm1.Resize; begin inherited; end; initialization Forms.RegisterForm({$I %FILE%}, TForm1); end. |
The final result
Now fire up your Delphi project, click the “start” button to initialize the server (note: the firewall may ask you to allow the server to use the port, remember to check “local networks” and just click “ok”). Your Delphi server should now run at port 8080 — use your favorite browser to check that it works. It should return “hello world” (see “HandleCommandGet” event handler in the Delphi code).
Next, fire up your Smart Mobile Studio project. Hit the “Connect” button, type something in the text-field and click “send” to ship it off to the server. Now watch the memo on the server and voila — you have just written your first websocket client/server system in less than 15 minutes!
Для просмотра ссылки Войди
Websocket has never been easier!
Note: Remember to use your local IP. The IP listed in the SMS example above is just a local address on my local network. If you are running Delphi and SMS on the same machine, just use 127.0.0.1 and bob’s your uncle.
[/SHOWTOGROUPS]