Page 1 of 1

Read / Write to SOCKET

Posted: Fri Jun 22, 2018 5:19 pm
by ace16vitamine
Dear all,

my application is sending informations (e.g. License Check) over a SOCKEZ to my Server.

App -> ask to check license -> Server -> Valid yes/No -> App

I do this simple with

Code: Select all

open socket to "localhost:8080"
write socketfile to socket "localhost:8080"
The Server is receiving the datas with

Code: Select all

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?

My first idea was on Server

Code: Select all

write socket theIP...
and on the Client

Code: Select all

read from socket "localhost:8080"...
but it seems that this does not work.

Any other Ideas how to solve this?

Stefan

Re: Read / Write to SOCKET

Posted: Fri Jun 22, 2018 5:33 pm
by dunbarx
Hi.

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.

Or not.

Craig Newman

Re: Read / Write to SOCKET

Posted: Fri Jun 22, 2018 7:04 pm
by ace16vitamine
but might you need to explicitly open a socket when you write back from the server?
maybe. In the final version the client is behind a NAT Firewall, initial TCP communication is not possible from Server to Client.
I don't use sockets,
Alternatives are welcome. :-)

Stefan

Re: Read / Write to SOCKET

Posted: Fri Jun 22, 2018 8:18 pm
by FourthWorld
Is there a reason why HTTP would not be a good protocol here?

Re: Read / Write to SOCKET

Posted: Fri Jun 22, 2018 11:55 pm
by ace16vitamine
hm, you are right and I can work with proxys. Do you now any example sources with livecode http communication?

Re: Read / Write to SOCKET

Posted: Sat Jun 23, 2018 2:29 pm
by AxWald
Hi,

since there's no full reply yet, and I just found I have one here collecting cobwebs, here we go:

The Server code:

Code: Select all

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
and Client code:

Code: Select all

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:

    Code: Select all

    [COMMAND],len(PAYLOAD) {CR}
    [PAYLOAD]
    Using an example from the server scripts MSGHandler function, it could look like this:
    --> Client sends: -->

    Code: Select all

    ART,9
    000521
    89
    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?"

    <-- Server replies: <--

    Code: Select all

    ART OK,11
    125.10
    1305
    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!