|
- Overview
- Operating mode
- Example
- Code for connecting to the server and for sending messages
- Code of return Callback procedure
- Example of WebSockets server developed in WINDEV
The WebSockets are used to communicate from a Web application (Intranet or Internet site run in a browser) to a Web server by using sockets. Remark: The WebSockets server can correspond to a WINDEV or WEBDEV application, or to another one. This page presents an example of WebSockets server developed in WLanguage with WINDEV. To send a message from a Web application by using the WebSockets, the following processes must be programmed on browser side: - connection to server,
- sending message,
- disconnection.
To do so, you will use the same WLanguage functions as the ones used on server side:
| | SocketConnect | Used to connect to the webSockets server. | SocketWrite | Used to send a message to the webSockets server. | SocketExist | Used to check whether the socket used by the connection was not already created. | SocketClose | Used to close the socket once the messages have been sent. |
Code for connecting to the server and for sending messages
SocketConnect("client", "ws://<ServerIPAddress>:5001", ReturnProc) // Remark: for a connection in safe mode, use 'wss' instead of 'ws' // SocketConnect("client", "wss://<ServerIPAddress>:5001", ReturnProc) // Caution: in server code, you must use // SocketCreateSSL instead of SocketCreate Info("Closing socket...") SocketClose("client")
Code of return Callback procedure
PROCEDURE ReturnProc(nEvent, sMessage) gsRes is string = "" SWITCH nEvent CASE SocketOpening: SocketWrite("client", "Text of message sent from the browser.") RETURN CASE SocketMessage: gsRes += [CR] + "Receiving message: " + sMessage CASE SocketClosing: gsRes += [CR] + "Closing the socket" CASE SocketError: gsRes += [CR] + "Error of socket: " + sMessage RETURN OTHER CASE END Info(gsRes)
Example of WebSockets server developed in WINDEV Let's see an example of code used to develop a WebSockets server with WINDEV. This code must be adapted according to your configuration and to your requirements (IP address of server, ports to open, ...). Before modifying this example, you must be familiar with the technique and theory of WebSockets. The purpose of this example is not to expliain the theorical operating mode of WebSockets. It just explains how to use WebSockets. To create a WebSocket server in WINDEV: - Create a WINDEV project.
- Create a blank window
- Create a local procedure (pServerSocketListen for example) to listen to the messages sent by the client from its Web site. The code of this local procedure is as follows:
// Code of local procedure: Listen to the messages sent by the socket client. PROCEDURE pServerSocketListen() HEADER_WEBSOCKET_CLIENT is string = "Sec-WebSocket-Key: " HEADER_WEBSOCKET_PROTOCOL is string = "Sec-WebSocket-Protocol: " // Create the socket server to listen to the incoming messages IF SocketCreate("Server", 5001) = False THEN Error("Creation error " + ErrorInfo(errMessage)) ELSE // Process (or thread) for listening to messages // This process is run in background task // Listen permanently because we don't know when a message arrives ThreadExecute("Thread1", threadNormal, WaitProcedure) END //----------------------------------------------------------- // Procedure called in the listening thread INTERNAL PROCEDURE WaitProcedure() // Endless loop in order to wait for a client connection. // As soon as a client connects to send a message, // a thread is started to manage the incoming messages. // The ProcedureManagement procedure manages the incoming messages. LOOP Multitask(0) IF SocketWaitForConnection("Server") THEN Channel is string Channel = SocketAccept("Server") SocketChangeTransmissionMode(Channel, SocketNoEndTag) ThreadExecute(Channel, threadNormal, ProcedureManagement, Channel) END END //-------------------------------------------------------------- // Code of procedure for managing the incoming messages INTERNAL PROCEDURE ManageProcedure(Channel) sRequest is ANSI string arrProtocol is array of strings sRes is string sProtocol is string = "JSON" // Read the socket until we reach the ending sequence of message // In our case, 2 CR characters in a row WHILE StringCount(sRequest, CR + CR) = 0 sRequest += SocketRead(Channel) END // Process the incoming request // The sRequest variable contains the message to process // Study the string sKey is ANSI string FOR EACH STRING sLine OF sRequest SEPARATED BY CR Trace(sLine) IF sLine [= HEADER_WEBSOCKET_CLIENT THEN sKey = sLine[[Length(HEADER_WEBSOCKET_CLIENT)+1 À]] ELSE IF sLine [= HEADER_WEBSOCKET_PROTOCOL // Retrieve the protocols StringToArray(ExtractString(sLine, 2, ":"), arrProtocol, ",") END END // Prepare the response that will be sent to the client sRes = [ HTTP/1.1 101 Web Socket Protocol Handshake Upgrade: websocket Connection: Upgrade WebSocket-Origin: <ServerIPAddress> WebSocket-Location: ws://<ServerIPAddress>:5001 Sec-WebSocket-Accept: %1 ] IF arrProtocol..Occurrence <> 0 THEN sRes += [CR] + "Sec-WebSocket-Protocol: %2" sProtocol = Upper(NoSpace(arrProtocol[1])) sRes = StringBuild(sRes, Crypt(HashString(HA_SHA_160, sKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"), "", compressNone, encodeBASE64), sProtocol + CR + CR) ELSE sRes = StringBuild(sRes, Crypt(HashString(HA_SHA_160, sKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"), "", compressNone, encodeBASE64) + CR + CR) END // Sends the response to the client SocketWrite(Channel, sRes) LOOP bufFrame is Buffer = SocketRead(Channel) IF 0 = Length(bufFrame) THEN Trace("Break") SORTIR END nFrameLength is int = Asc(bufFrame[[2]]) & 127 bufMask is Buffer bufData is Buffer IF 126 = nFrameLength THEN nFrameLength = HexaToInt( BufferToHexa(bufFrame[[3 ON 2]])) //BufferToInt(bufFrame, 3, 2) bufMask = bufFrame[[5 TO 8]] bufData = bufFrame[[9 TO]] ELSE IF 127 = nFrameLength THEN nFrameLength = HexaToInt(BufferToHexa(bufFrame[[3 ON 8]])) bufMask = bufFrame[[11 TO 14]] bufData = bufFrame[[15 TO]] ELSE bufMask = bufFrame[[3 TO 6]] bufData = bufFrame[[7 TO]] END sText is ANSI string FOR i = 1 _TO_ Length(bufData) sText += Charact(BinaryXOR( Asc(bufData[[i]]), Asc(bufMask[[(i - 1) modulo 4 + 1]]))) END Trace(UTF8ToAnsi(sText)) // Format the response SWITCH sProtocol CASE "XML" sRes = [ <XML status="ok"> %1 </XML> ] CASE "JSON" sRes = [ {"status": "ok", "response": "%1" } ] OTHER CASE sRes = StringToUTF8("Format not supported!") END sRes = StringBuild(sRes, sText) nResponseLenght is int = Length(sRes) bufResponse is Buffer bufResponse[[1]] = Charact(BinaryOR(0x80, BinaryAND(0x1, 0xF))) IF nResponseLength <= 125 THEN bufResponse[[2]] = Charact(nResponseLength) ELSE IF nResponseLength <= 65536 THEN bufResponse[[2]] = Charact(126) // The writing of the length is missing bufResponse += HexaToBuffer(Right(IntToHexa(nResponseLength), 4)) ELSE bufResponse[[2]] = Charact(127) // The writing of the length is missing bufResponse += HexaToBuffer(IntToHexa(nResponseLength)) END SocketWrite(Channel, bufResponse + sRes) END END END
|
|
|
|
|
|
|