B4J Question WebSocket server send & receive text

lemonisdead

Well-Known Member
Licensed User
Longtime User
Hello,
First of all, I would like to apologize for the question. I am currently trying to port some code (to study if I could migrate existing projects to B4J and forget other tools I do already use). But, as usual, I am lost because the available examples are too complete.

Please, what could be the smallest websocket server code to send and receive strings between a B4J server and an existing HTML5 app ?

In another language I am used to, it is

B4X:
on StartUP 'sub executed when the program starts
hide this stack 'this because the language used is based on stacks and has a GUI by default
accept connections on port 8000 with message "clientConnected"  'starts the socket server
end StartUP

on clientConnected pSocket
read from socket pSocket with message "messageReceived" 'will call the sub when a client is connected
end clientConnected

on messageReceived pSocket, pMsg 'psocket is the socket, pMsg is the message's string
write pMsg to socket pSocket 'sends the message back
read from socket pSocket with message "messageReceived"  'creates the loop to receive
end messageReceived

Many thanks (and please, please, don't forward me to a tutorial (I think I did read them all, downloaded the code trying not to have to post this thread)
 

Roycefer

Well-Known Member
Licensed User
Longtime User
Did you write this existing HTML5 app? Of what does it consist? Is it just the HTML5 front-end? To have an HTML5 app communicate with a B4J server via WebSockets, that HTML5 app must have this line:
B4X:
<script src="b4j_ws.js"></script>
or something equivalent and then you have to host the b4j_ws.js JavaScript file on your server (in the root of the statics folder as in this example).

In your main module, you would have this code:
B4X:
Sub Process_Globals
   Dim srvr as Server
End Sub

Sub AppStart(Args() as String)
   srvr.Initialize("srvr")
   srvr.AddWebsocket("/SampleWS", "SampleWS")
   srvr.Port = 8000
   srvr.Start
   StartMessageLoop
End Sub
Then you would create a WebSocketClass module called "SampleWS" as follows:
B4X:
'WebSocket class
Sub Class_Globals
    Private ws As WebSocket
End Sub

Public Sub Initialize
End Sub

Private Sub WebSocket_Connected (WebSocket1 As WebSocket)
    ws = WebSocket1
    Log("SampleWS connected: " & DateTime.Time(DateTime.Now))
    ws.RunFunction("ClientGetsString", Array("this is a sample message sent from the server"))
    ws.Flush
End Sub

Private Sub WebSocket_Disconnected
    Log("SampleWS disconnected: " & DateTime.Time(DateTime.Now))
End Sub

Sub fromUser_LogThisString(params as Map)
    Dim sampleString as String = params.Get("sample")
    Log("Sample String: " & sampleString)
End Sub
This WebSocket will call a method in the client's browser called "ClientGetsString()" (provided you have written such a function in your HTML5 app) as soon as a connection is established. Additionally, the HTML5 app can raise an event called "fromUser_LogThisString" that will output the String to the Log(). This can be called in JavaScript in your HTML5 app as such:
B4X:
b4j_raiseEvent("fromUser_LogThisString", {sample:"This is a sample message sent from the client"});

Also, in your client code, you should call
B4X:
b4j_connect("/SampleWS")
inside your $(document).ready() function in order to connect to your SampleWS WebSocket.

Additionally, you can execute arbitrary code in the client by calling ws.Eval().
 
Upvote 0

lemonisdead

Well-Known Member
Licensed User
Longtime User
Hello @Roycefer
First of all, thanks for the clear and documented reply. No, I have not developed that HTML5 app, reason why I can not go with webapps (or I would have to rewrite it from zero). It is a some sort front app and I have some settings available in an options file.
Those settings are the websocket server's IP, port, secured or not, the choice for GET or POST methods (it is not a http request by the way), etc.

And that's the reason why I could not use the RunFunction command and tried to recreate what I did already with my previous tool (I have created a socket server which receives the requests and returns the information required). But it seems to be harder (or not so simple) with B4J till I don't get the way to simply send a text reply.

I will continue to try to understand. Thanks a lot again :)
 
Upvote 0

Roycefer

Well-Known Member
Licensed User
Longtime User
Do you have no ability or permission to modify the HTML5 app? Making it B4J-compatible may just require adding that single <script src=.....> line, the b4j_connect() call and then some knowledge of the app's DOM (everything server-side would then be accomplished with ws.Eval()). Otherwise, it looks like you have to use Reflection or JavaObject to access the underlying Jetty WebSocket objects and send raw bytes, which sounds pretty ugly. I haven't attempted that approach so I can't even say whether it will work or not.
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
But it seems to be harder (or not so simple) with B4J till I don't get the way to simply send a text reply.
B4J WebSockets work in a higher level. All the interactions are expected to go through the b4j_ws JavaScript. This makes it simple to interact directly with the DOM elements as if you are running local JavaScript code.

If you can add some JavaScript code then it is trivial to send text with RunFunction (there are other ways as well).
 
Upvote 0
Top