Got a LiveCode personal license? Are you a beginner, hobbyist or educator that's new to LiveCode? This forum is the place to go for help getting started. Welcome!
accept connections on port 8080 with message "someoneConnected"
on someoneConnected theIP
read from socket theIP until "EOL*" with message "newMessage"
end someoneConnected
This is also working
But how can I write an answer from Server to client?
I don't use sockets, but might you need to explicitly open a socket when you write back from the server? In other words, it may not be true that just because you opened a socket between those two systems in one direction, that socket was automatically set up to communicate in the other direction.
global gRunning, gPort
on ServerStart
put "8080" into gPort -- or whatever portNum you choose
if not gRunning then
put true into gRunning
accept connections on port gPort with message "ClientConnect"
end if
end ServerStart
on ClientConnect theSock
put "Hello!" into MyMsg
write "CON OK, " & length(MyMsg)& return & MyMsg to socket theSock
read from socket theSock until return with message "MsgReceive"
end ClientConnect
on MsgReceive theSock, theMsg
put item 1 of line 1 of theMsg into MyCmd -- CMD received
put Item 2 of line 1 of theMsg into MyLen -- Length(Payload)
read from socket theSock for MyLen chars -- get the Payload
put it into myPL
-- here we process the client request:
put MSGHandler(MyCmd,myPL) into MyResult -- handle a Cmd
-- //
write MyCmd & " OK," & length(MyResult) & return & MyResult to socket theSock -- and reply
read from socket theSock until return with message "MsgReceive"
end MsgReceive
function MSGHandler theCmd, thePL
switch theCmd
case "ART"
-- an example - we have an article number and the customers price group,
-- and want the currently available amount of the article, and the custom price for our customer
put line 1 of thePL into myArtNum -- the article number
put line 2 of thePL into myPriceGroup -- the price group
put "SELECT `article`.price, `supply`.available " & \
"FROM `article` LEFT JOIN `supply` ON `article`.id = `supply`.article " & \
"WHERE `article`.number = '" & myArtNum & "';" into StrSQL
put getSQL("WEBDB",StrSQL) into myArtData
-- using our "getSQL interface" (it does all the db stuff)
-- we ask our "WebDB" for the base price of the article & its available amount
set itemdel to tab
put item 1 of myArtData into myPrice
put item 2 of myArtData into myAvail
put "SELECT mod FROM `pricegroups` " & \
"WHERE `pricegroups`.id = " & myPriceGroup & ";" into StrSQL
put getSQL("CACHE",StrSQL) into myPMod
-- we check our cache SQLite for the suitable price modificator
put round(myPrice * myPMod,2) into myPrice
return myPrice & return & myAvail -- answer with the desired data
break
case "CUS"
-- ...
break
default
return empty
end switch
end MSGHandler
global gSocket, gPort
on StartCon theServer
if gPort is empty then put "8080" into gPort -- or whatever portNum you choose
if gSocket is empty then
open socket to theServer & ":" & gPort with message "ServerConnect"
end if
put "Connected to server " & theServer & return after field "logFld"
end StartCon
on ServerConnect theSocket
put theSocket into gSocket
read from socket gSocket with message "MsgReceive"
put "Server accepted me!" & return after field "logFld"
end ServerConnect
on MsgReceive theSocket, theMsg
put "<- : " & theMsg & return & "----------" & return after field "logFld"
read from socket theSocket with message "MsgReceive"
end MsgReceive
on MsgSend
-- a button will call this
put fld "CmdToSend" into myCmd -- A command, so the server knows what to do with the msg
put fld "DataToSend" into myPayLoad -- additional data that the server requires to do it's work
if gSocket is not empty then
put myCmd & "," & length(myPayLoad) & return & myPayLoad into myData
write MyData to socket gSocket
end if
put "-> : " & myData & return after field "logFld"
end MsgSend
This needs some additional information:
To make communication possible a common protocol (= language) is desirable. Here we use a very simple but versatile one:
Translate: "I have ARTiclenumber 000521 and a customer with a pricegroup of 89 - how much this customer must pay, and how much of this article is available?"
Translate: "Your request has been considered OK - the price is 125.10 and we have 1305 of the article left."
So "COMMAND" designates what to do with the data, len(PAYLOAD) is used to determine the boundaries of the data for easy reading, and "PAYLOAD" is the data itself.
.
The Server code contains a function "MSGHandler" with an example command. I hope it's comprehensible what it does :)
Besides, I'd always use a local SQLite db (maybe replicated) as cache - it's this much faster! Any calls to remote dbs (as in the example) will be a serious bottle neck to the immense possible speed of the socket server.
.
The code is based on an actual implementation of a socket server that runs 24/7/365 for quite some years now. It connects a web shop to an in-house Server (Single Xeon 3GHz) and handles authorizations, customer specific "special offers" & prices and the orders - the web shop itself has no customer data, no prices, nothing sensible in its db. All that is provided by the socket server.
.
Disclaimer:
The code should run, but I haven't tested it. It may contain typos, misspelled variable names, unavoidable nonsense and such. And I have removed all & any error checking, to make more understandable how it works.
Have fun!
All code published by me here was created with Community Editions of LC (thus is GPLv3).
If you use it in closed source projects, or for the Apple AppStore, or with XCode
you'll violate some license terms - read your relevant EULAs & Licenses!