B4J Library xSocket - The socket library is fully functional for event and semantic message streams

xSocket is a library wrapped around Socket.d.
Socket.d has a collection of many connection protocols: TCP, UDP and WS. It can be used for MSG, RPC, IM, MQ and other scenarios, and can replace Http, Websocket, gRpc and other protocols. Such as the connection between the mobile device and the server, such as some microservice scenarios, etc.

Main Features​

  • Event-based, each message can be event-routed
  • The so-called semantics is described by the meta-information
  • Stream dependency, where related messages are strung together in a stream
  • Language independent, binary transport (tcp, ws, udp) Support multi-language, multi-platform
  • Disconnection reconnection, automatic connection restoration
  • Multiplexing, allowing multiple request and response messages to run simultaneously on a single connection
  • Two-way communication, single link two-way listening and sending
  • Automatic sharding,Data over 16Mb (configurable) will be automatically split and reassembled (except udp)
  • Simple interface, reactive but with callback interface

* Extends Java: https://drive.google.com/file/d/1LfFh1KWbz3lGbPMLGDRZqxjPE65_SdM5/view?usp=sharing

* Language supported: B4X, .NET, Javascript, PHP;

There are fully functional xSocket supported:
- Send (Qos0) : Yes
- SendAndRequest (Qos1) : Yes
- SendAndSubscribe (stream) : Yes
- Reply or respond : Yes
- Single connection two-way communication : Yes
- Data sharding : Yes
- Disconnection automatically reconnect : Yes
- Meta information : Yes
- Event(or path): Yes
- StreamId (or message correlation): Yes
- Broker pattern cluster: Yes
- Asynchronous: Async
- Interface experience: Classic
- Basic transport protocol: tcp, udp, ws

* The library and examples are still in development, but they will be ready in about 1-2 days.
 

Attachments

  • TCP_Server_Example.zip
    4.6 KB · Views: 28
  • TCP_Client_Example.zip
    231.1 KB · Views: 29
  • xSocket (3).zip
    14.4 KB · Views: 24
Last edited:

tummosoft

Member
Licensed User
Longtime User
Server example:

Create xServerSockets:
Dim server As xServerSockets
server.Initialize("server", "tcp") ' udp, ws
    server.SetCharset("UTF-8")
    server.Start(51042)
    StartMessageLoop
    
    Sub server_OnConnected(status As Boolean, SessionId)
    Log("Server connected:" & status)
    Log("SessionId:" & status)
    
End Sub

Sub server_OnRequest(ByteMessage() As Byte, StringMessage As String, EventName As String, Meta As Map)
    Log("StringMessage" & StringMessage)
    Log("EventName" & EventName)
    server.SendReplyRequest("I am a boss")
    
    Dim mData As Map = Meta
    
    Log("SIZE=" & mData.Size)
    Log("VALUE OF=" & mData.Get("Key 1"))
End Sub

Sub server_OnSimpleMessage(StringMessage As String, EventName As String, Meta As Map)
    Log("StringMessage=" & StringMessage)
    Log("EventName=" & EventName)
    
    Dim mData As Map = Meta
    
    Log("SIZE=" & mData.Size)
    Log("VALUE OF=" & mData.Get("Key 1"))
End Sub
 

tummosoft

Member
Licensed User
Longtime User
Client Example
xScoket Client:
client.Initialize("client", 51042, "tcp://127.0.0.1")
client.Send("event/demo","I am Vietnamese")

Private Sub btStart_Click
    
    client.Send("event/demo","I am Vietnamese")
End Sub

Sub client_onconnected(status As Boolean, SessionId)
    Log("status=" & status)
    Log("SessionId=" & SessionId)
End Sub

Private Sub btSendText_Click
    Dim mData As Map
    mData.Initialize
    mData.Put("key 1", "value 1")
    mData.Put("key 2", "value 2")
    client.SendAndRequest("/hasmap/v12", "There are maps data", mData)
End Sub

Private Sub btSendFile_Click
    
End Sub

Sub client_OnMessage(ByteMessage() As Byte, StringMessage As String)
    Log("Message=" & StringMessage)
End Sub
 

tummosoft

Member
Licensed User
Longtime User
Example of send files, automating server control using TCP protocol

We created an example of sending files over TCP sockets, as well as creating an automation robot for multidimensional communication with a TCP server.

- The following libraries are required
* Extends jar (jFileSupport)
* Date Time Utils library for B4X

Chat:
Dim plancurrent As Plan =  serverScript.Get(currentID)
    Dim plantime As Long = plancurrent.time
    
    lblServertime.Text = DateTime.Time(DateTime.Now)
    
    
    Dim ntime As Long = DateTime.Now
        
    
    If ntime > plantime Then
        console.Append(jDate1.toString).Append(CRLF)
        console.Append("You: ").Append(TAB).Append(plancurrent.request).Append(CRLF)
        If (plancurrent.event = "/message") Then
            socketClientTCP.SendAndRequest("/message", plancurrent.request, meta)
            console.Append("----- Robot send a message").Append(CRLF)
            
        else If (plancurrent.event = "/action") Then
            socketClientTCP.SendAndRequest("/action", plancurrent.request, meta)                   
        else If (plancurrent.event = "/close") Then
            socketClientTCP.Close           
        
        End If
        
        TextArea1.Text = console.ToString
        currentID = currentID + 1
    End If
    
    If currentID = maxEvent Then
        timerAction.Enabled = False
    End If

How to send file over TCP:
Dim path As String = attach.Combine("D:\ANDROID\JAVALIBS\ImageSupport\xSocKet\TCP_Server_Example", "documents.txt")
socketClientTCP.SendFile("/sendfile", path)

OnMessage:
Sub socketClientTCP_OnMessage(ByteMessage() As Byte, StringMessage As String)
    Log("Message=" & StringMessage)
    console.Append("Boss: ").Append(TAB).Append(StringMessage).Append(CRLF)
    TextArea1.Text = console.ToString
    
End Sub

Client automatic script:
Sub Script
    Dim toTextEare As StringBuilder
    toTextEare.Initialize
    
    Dim jtime As jtime4x
    Dim jDate1 As jDate
    jDate1.Initialize
    
    Dim myPlan As Plan
    myPlan.Initialize
    
    myPlan.id = 0
    
    myPlan.sockettype = "simple"
    myPlan.event = "/message"
    myPlan.request = "Hello! I am a client!"   
    jDate1.JavaDate = jtime.plusMinutes(jtime.NowUTC, 0.5)
    myPlan.time = jDate1.toLong
    serverScript.Add(myPlan)
    toTextEare.Append(jDate1.toString).Append(TAB).Append(myPlan.request).Append(CRLF)
    
    Dim myPlan As Plan
    myPlan.Initialize
    myPlan.id = 1   
    myPlan.sockettype = "simple"
    myPlan.event = "/message"
    myPlan.request = "Hello! How are you"   
    jDate1.JavaDate = jtime.plusMinutes(jtime.NowUTC, 0.8)
    myPlan.time = jDate1.toLong
    serverScript.Add(myPlan)
    toTextEare.Append(jDate1.toString).Append(TAB).Append(myPlan.request).Append(CRLF)
        
    Dim myPlan As Plan
    myPlan.Initialize
    myPlan.id = 2   
    myPlan.sockettype = "request"
    myPlan.event = "/action"
    myPlan.request = "I want to send you a document"
    
    jDate1.JavaDate = jtime.plusMinutes(jtime.NowUTC, 1.2)
    myPlan.time = jDate1.toLong
    serverScript.Add(myPlan)
    toTextEare.Append(jDate1.toString).Append(TAB).Append(myPlan.request).Append(CRLF)
    
    Dim myPlan As Plan
    myPlan.Initialize
    myPlan.id = 3
    myPlan.sockettype = "request"   
    myPlan.event = "/verification"
    myPlan.request = "This is MD5 of document file"
    
    jDate1.JavaDate = jtime.plusMinutes(jtime.NowUTC, 1.3)
    myPlan.time = jDate1.toLong
    serverScript.Add(myPlan)
    toTextEare.Append(jDate1.toString).Append(TAB).Append(myPlan.request).Append(CRLF)
    
    Dim myPlan As Plan
    myPlan.Initialize
    myPlan.id = 4
    myPlan.sockettype = "request"   
    myPlan.event = "/sendfile"
    myPlan.request = "I am ready!"   
    jDate1.JavaDate = jtime.plusMinutes(jtime.NowUTC, 1.4)
    myPlan.time = jDate1.toLong
    serverScript.Add(myPlan)
    toTextEare.Append(jDate1.toString).Append(TAB).Append(myPlan.request).Append(CRLF)
    
    Dim myPlan As Plan
    myPlan.Initialize
    myPlan.id = 5   
    myPlan.sockettype = "request"
    myPlan.event = "/close"
    myPlan.request = "Bye! Bye!"   
    jDate1.JavaDate = jtime.plusMinutes(jtime.NowUTC, 1.6)
    myPlan.time = jDate1.toLong
    serverScript.Add(myPlan)
    toTextEare.Append(jDate1.toString).Append(TAB).Append(myPlan.request).Append(CRLF)
    
    maxEvent = 6
    TextArea2.Text = toTextEare.ToString
End Sub

 

Attachments

  • Server Examples.zip
    4 KB · Views: 24
  • TCP_Automatic_Communication.zip
    4.2 KB · Views: 26
  • xSocket (2).zip
    8 KB · Views: 22
  • jTime.zip
    7.7 KB · Views: 21
  • jFileSupport.zip
    52.9 KB · Views: 26

peacemaker

Expert
Licensed User
Longtime User
Wow, it looks like huge work !
Are these libs compatible with B4A, B4i too ?
 

tummosoft

Member
Licensed User
Longtime User
* WebSocket: Example of how to send files via Javascript


xSocket Server:
Sub server_OnConnected(status As Boolean, SessionId As String)
    Log("Server connected:  " & status)
    Log("Has a connected:   " & SessionId)
    
    ' Set events for each path. Example http://127.0.0.1:51042/room1
    
End Sub

Sub server_OnRequest(StringMessage As String, data() As Byte, EventName As String, Meta As Map)
    Dim u As String = srvr.getPararam("u")
    Dim p As String = srvr.getPararam("p")
    Dim token As String = srvr.getPararam("token")
    
If (EventName = "/login") Then       
    CheckUser(token, u, p)   
else if (EventName = "/room1") Then
    If (CheckUser(token, u, p)) Then
            srvr.SendReply("Congratulations! Successful login!")
    End If
else if (EventName.StartsWith("/sendfile")) Then   
    
    If (data <> Null) Then
            Dim filename As String = Meta.Get("FILE_NAME")
            Log("FILE_NAME= " & filename )
            Log("LENGTH= " & data.Length)
            File.WriteBytes("D:\", filename, data)
            Log("------- save")
    End If
        
        
        
End If
    
End Sub

Sub CheckUser(token As String, user As String, pass As String) As Boolean
    
        If token <> "" Then
            If (session_manager.ContainsKey(token) = False) Then
                Dim usera As userInfo
                usera.Initialize
                usera.username = user
                usera.userpass = pass
                usera.status = True
                session_manager.Put(token, usera)
                srvr.SendReply("Login success")
            Else
                srvr.SendReply("User has login....")
            End If
        Else
        srvr.SendReply("Please register!")
    End If
End Sub

Sub server_OnSimpleMessage(StringMessage As String, EventName As String, Meta As Map)
    Log("NEW=" & StringMessage)
End Sub

Sub server_OnReceiveBytes(data() As Byte, EventName As String, Meta As Map)
    Log("Client send me a file...")
    If (EventName = "/sendfile") Then
        File.WriteBytes("D:\", Meta.Get("FILE_NAME"), data)
        Log("------- save")
    End If
    
End Sub

Javascript:
let isOpen = false;

window.onload = mainDo;

async function open(callback) {
    let serverUrl = document.getElementById("serverUrl").value;
    if (!serverUrl) {
        alert('serverUrl cannot be empty!');
        return;
    }
    await SocketD.createClient(serverUrl.trim())
        .config(c => c
            .heartbeatInterval(1000*5)
            .fragmentSize(1024 * 1024)
            .metaPut("test","1"))
        .connectHandler(c=> {
            console.log("connect begin...");
            c.getConfig().metaPut("test","1");
            return c.connect();
        })
        .listen(SocketD.newEventListener()
            .doOnOpen(s=>{
                window.clientSession = s;
                console.log("outmeta: test=" + s.handshake().param("test"))
            })
            .doOnMessage((s, m) => {
            appendToMessageList('Receive push', m.dataAsString());
        }))
        .open();
    console.log('session', clientSession);
    if (callback) callback();
}

function close(callback) {
    clientSession.close();
    if (callback) callback();
}

function send(type) {
    let input = document.getElementById("input").value;
    if (!input) {
        alert("Input message cannot be empty!");
        return;
    }


    if (type == 1) {
        appendToMessageList('Send and request', input);
        clientSession.sendAndRequest("/login", SocketD.newEntity(input)).thenReply(reply => {
            console.log('reply', reply);
            appendToMessageList('reply', reply.dataAsString());
        });
    } else if (type == 2) {
        appendToMessageList('Send and subscribe', input);
        clientSession.sendAndSubscribe("/demo", SocketD.newEntity(input)
            .metaPut(SocketD.EntityMetas.META_RANGE_SIZE,"3")).thenReply(reply => {
            console.log('reply', reply);
            if(reply.isEnd()){
                appendToMessageList('End of reply', reply.dataAsString());
            }else{
                appendToMessageList('reply', reply.dataAsString());
            }
        });
    } else {
        appendToMessageList('Login', input);
        clientSession.send("/room1", SocketD.newEntity(input));
    }
}

function appendToMessageList(hint, msg) {
    let ele = document.getElementById("message");
    ele.value = `[${dateFormat(new Date(), 'yyyy-MM-dd hh:mm:ss.SSS')}] ${hint}:${msg}\n` + ele.value;

}



function mainDo() {
    let openBtn = document.getElementById("openBtn");
    openBtn.addEventListener("click", function () {
        if (isOpen) {
            close(() => {
                openBtn.innerHTML = 'connect';
                isOpen = false;
            });
        } else {
            open(() => {
                openBtn.innerHTML = 'closure';
                isOpen = true;
            });
        }

    });
    let send0 = document.getElementById("send");
    let send1 = document.getElementById("sendAndRequest");
    let send2 = document.getElementById("sendAndSubscribe");
    send0.addEventListener("click", () => {
        if (isOpen) {
            send(0);
        }
    });

    send1.addEventListener("click", () => {
        if (isOpen) {
            send(1);
        }
    });

    send2.addEventListener("click", () => {
        if (isOpen) {
            send(2);
        }
    });


    let push = document.getElementById("push");
    let unpush = document.getElementById("unpush");

    push.addEventListener("click", () => {
        if (isOpen) {
            clientSession.send("/room1", SocketD.newEntity());
        }
    });

    unpush.addEventListener("click", () => {
        if (isOpen) {
            clientSession.send("/unpush", SocketD.newEntity())
        }
    });


    let uploadFile = document.getElementById("uploadFile");
    let downloadFile = document.getElementById("downloadFile");
    let uploadData = document.getElementById("uploadData");
    uploadFile.addEventListener("click", async () => {
        if (isOpen) {
            const files = document.getElementById("file").files;
            if (!files || files.length == 0) {
                alert("Please select file");
                return;
            }

            const file1 = document.getElementById("file").files[0];

            appendToMessageList('Send files and request', file1.name);                   
            clientSession.sendAndRequest("/sendfile", SocketD.newEntity(file1).metaPut("FILE_NAME",file1.name), 100_000).thenReply(reply => {
                console.log('reply', reply);
                appendToMessageList('reply', reply.dataAsString());
            }).thenProgress((isSend, val, max) => {
                if (isSend) {
                    appendToMessageList('Send progress', val + "/" + max);
                }
            });
        }
    });

    downloadFile.addEventListener("click", async () => {
        if (isOpen) {
            appendToMessageList('download file', "...");
            clientSession.sendAndRequest("/download", SocketD.newEntity()).thenReply(reply => {
                console.log('reply', reply);

                const fileName = reply.meta(SocketD.EntityMetas.META_DATA_DISPOSITION_FILENAME);
                if (fileName) {
                    appendToMessageList('download file', "file=" + fileName + ", size=" + reply.dataSize());
                } else {
                    appendToMessageList('download file', "No files received :(");
                }
            }).thenProgress((isSend,val,max)=>{
                if(!isSend){
                    appendToMessageList('Download progress', val + "/" + max);
                }
            });
        }
    });

    uploadData.addEventListener("click", async () => {
        if (isOpen) {
            const strSize = 1024*1024*10;
            let str = "";
            while (str.length < strSize) {
                str += "1234567890"
            }

            appendToMessageList('Submit large text block 10M', "...");
            clientSession.sendAndRequest("/upload", SocketD.newEntity(str)).thenReply(reply => {
                console.log('reply', reply);
                appendToMessageList('reply', reply.dataAsString());
            }).thenProgress((isSend, val,max)=> {
                if(isSend){
                    appendToMessageList('Submit progress', val + "/" + max);
                }
            });
        }
    });
}

//Date formatting
function dateFormat(date,fmt) {
    //default format
    fmt = fmt ? fmt : 'yyyy-MM-dd hh:mm:ss';

    var o = {
        "M+" : date.getMonth()+1,                 
        "d+" : date.getDate(),                   
        "h+" : date.getHours(),                   
        "m+" : date.getMinutes(),                 
        "s+" : date.getSeconds(),               
        "q+" : Math.floor((date.getMonth()+3)/3),
        "S+"  : date.getMilliseconds()             
    };
    if(/(y+)/.test(fmt)) {
        fmt=fmt.replace(RegExp.$1, (date.getFullYear()+"").substr(4 - RegExp.$1.length));
    }
    for(var k in o) {
        if(new RegExp("("+ k +")").test(fmt)){
            fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (o[k]) :
                RegExp.$1.length==2 ? (("00"+ o[k]).substr((""+ o[k]).length)) : (("000"+ o[k]).substr((""+ o[k]).length))
            );
        }
    }
    return fmt;
}
 

Attachments

  • demo01-js-ws.zip
    17.8 KB · Views: 23
  • xSocket (3).zip
    14.4 KB · Views: 24
  • ws_sendfiles_server.zip
    3.8 KB · Views: 25
Top