|
|
|
|
- Presentación
- Modo de funcionamiento
- Ejemplo
- Código para conectarse al servidor y para enviar mensajes
- Código de retorno Callback Procedure
- Ejemplo de servidor WebSockets desarrollado en WINDEV
Administración de WebSockets
Los WebSockets se utilizan para comunicarse desde una aplicación Web (sitio INTRANET o INTERNET ejecutado en un navegador) a un servidor Web mediante el uso de sockets. Observación: El servidor WebSockets puede corresponder a una aplicación WINDEV o WEBDEV, o a otra.. Esta página presenta un ejemplo de servidor WebSockets desarrollado en WLanguage con WINDEV. Para enviar un mensaje desde una aplicación Web utilizando los WebSockets, se deben programar los siguientes procesos en el lado del navegador: - conexión al servidor,
- enviando un mensaje,
- desconexión.
Para ello, utilizará las mismas funciones de WLanguage que las que se utilizan en el lado del servidor:
| | SocketConnect | Se utiliza para conectarse al servidor webSockets. | SocketWrite | Se utiliza para enviar un mensaje al servidor webSockets. | SocketExist | Permite comprobar si la toma de corriente utilizada por la conexión no estaba ya creada.. | SocketClose | Permite cerrar el socket una vez enviados los mensajes. |
Código para conectarse al servidor y para enviar mensajes 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")
Código de retorno 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)
Ejemplo de servidor WebSockets desarrollado en WINDEV Veamos un ejemplo de código usado para desarrollar un servidor WebSockets con WINDEV. Este código debe ser adaptado según su configuración y sus necesidades (IP Address del servidor, puertos a abrir, ...). Antes de modificar este ejemplo, debe estar familiarizado con la técnica y la teoría de WebSockets. El propósito de este ejemplo no es explicar el modo de funcionamiento teórico de los WebSockets. Sólo explica cómo usar WebSockets. Para crear un servidor WebSocket en WINDEV: - Crear un proyecto WINDEV.
- Cree una ventana en blanco
- Crear un Procedure local (pServerSocketListen por ejemplo) para escuchar los mensajes enviados por el cliente desde su sitio web. El código de este Procedure local es el siguiente:
// 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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|