Add a WebSocket client component
See RFC 6455 (http://tools.ietf.org/html/rfc6455).
Hi, so I`m building a WebSocket client inherited from TIdTCPClient, how can I contribute to Indy project? I named it TIdSimpleWebSocketClient (I'm accepting suggestions to it's name) main methods:
Type
TSWSCDataEvent = procedure(Sender: TObject; const Text: string) of object;
...
Type TIdSimpleWebSocketClient = class(TIdTCPClient)
...
onDataEvent:TSWSCDataEvent;
property HeartBeatInterval: Cardinal read FHeartBeatInterval write FHeartBeatInterval;
property AutoCreateHandler: Boolean read FAutoCreateHandler write FAutoCreateHandler;
procedure writeText(pMsg:String);
procedure sendText(pMsg:String);
function ConnectToAndUpgrade(pURL:String):Boolean;overload;
...
It already works fine for ws and wss servers, and I'm using in an production environment
Thanks
What's the difference between writeText() and sendText()? What about sending binary data? Why doesn't onDataEvent differentiate between text and binary data? Why ConnectToAndUpgrade() instead of just overriding Connect()? In any case, to contribute, you can send the code to me privately, or submit a pull request on GitHub. But from the looks of it, your implementation might be a little too simple and will likely need tweaking before it can be committed.
Basically writeText() and sendText() do the same thing, its because I was working with Blackbox trial, and wanted to keep compatible with.
I`ll change somethings, and send you an copy.
Hi can you please give a look? https://github.com/arvanus/Indy/blob/WebSocketImpl/Lib/Core/IdWebSocketSimpleClient.pas Any suggestions are welcome so that I can pull-request
Sorry, I just haven't had any free time to look at it yet, but it is on my todo list to get to it. You didn't have to retract your pull request.
Ok, I just need one suggestion from you, to keep it consistent with Indy patterns. Websocket protocol accepts both binary and text messages, How do you suggests me to implement the methods? Implement 2 methods "write" with different parameters (overloaded), one receiving strings directly, and the other receiving TIdBytes array (or stream array)? Or declare "writeString" and "writeBinary" (or something like this)? Because both methods has different headers inside websocket frame.
Thanks!
The only difference between a "text" frame and a "binary" frame is the opcode used and the format of the payload, the rest of the frame data is the same between them.
It is really up to you to decide what you want to name the methods. You could use Write() overloads, like TIdIOHandler does. Or you could use separate names like SendString() and SendBuffer(), like TIdUDPBase does. I would probably stay away from using "binary" though, as nothing in Indy uses that term.
Easy WebSocket support with existing TidHTTPServer component :)
TWebSocket turn a idHTTPServer GET request into a WebSocket dialog.
https://github.com/tothpaul/Delphi/tree/master/idWebSocket
Hello,
Any update of IdWebSocketSimpleClient ? And and process of the websocket client of Indy?
Thanks
@arvanus Hello, When I use IdWebSocketSimpleClient, and connect to a ws:// URI, sometimes I get a warning message of "duplicates not allowed". Do you know what's the matter?
Thank you.
Hi @wqmeng, can you give me some details of when this error occurs? Exactly at connection, is it right?
@arvanus Mostly, it will happen at the first time the websocket connect to the URI. Then I close, and do connect again, it will not happen again. But if I exit the app or Kill it from the Android system, again reopen the App to connect the websocket server again, It will mostly show the "Duplicates not allowed" again.
Sometimes, I can see the exception can be out from the OnError event.
Thanks
Question: Are you using Apache as a reserve proxy? I've got some problems because Apache reused the socket from the last connection disconnected by another client. If so you'll need to disallow socket reuse, read here: https://github.com/ratchetphp/Ratchet/issues/645 and here: https://httpd.apache.org/docs/2.4/mod/mod_proxy.html
@arvanus Hello, no, I use https://github.com/swoole/swoole-src as a PHP websocket server.
Not sure if it reuse the socket. I use IdWebSocketSimpleClient on a Android phone.
So are you connecting directly? Swoole supports SSL connection directly ?
Yes, I connect directly.
And I do not use SSL in my case. Just ws://
Any update of IdWebSocketSimpleClient ? And and process of the websocket client of Indy?
No, not yet, sorry.
Hi, I need to connect to a WebSockets server running in a Lazarus FPC application. The server is running locally in a single machine, I'm currently using it from a localhost web application that runs on any browser and works fine.
I want to run a WebSockets client for that server, in a Delphi Android application. I will try the idWebSocketSimpleClient today and then I will report if it works.
Guten Tag,
vielen Dank für Ihre E-Mail.
Ich bin in den Skiferien von Montag, 27. Januar bis Sonntag, 2. Februar 2020. Die eingehenden E-Mails werden während dieser Zeit nicht bearbeitet.
Wenn es kein persönliches Anliegen ist, wenden Sie sich doch bitte an [email protected] oder an [email protected]
Herzlichen Dank für Ihr Verständnis.
Schöne Grüsse Elias Zurschmiede
delight software gmbh
I can connect to the websocket, I'm receiving the connection changes with onConnectionDataEvent, but onDataEvent is not receiving nothing, also onError displays nothing...
@lainz are you sure the server are sending you info? Try testing with https://websocket.org/echo.html demo service
I'm sure, since I'm using it with a Lazarus application that's used every day, so the web application is sending the data...
I get a connection, but after some time of no action (perhaps the heartbeat interval), the client doesn't receive the next message. If i send again a message, this works. (But the missing message didn't appear) Any suggestions?
I have not reviewed this code for errors, but that sounds like an issue with it not reading WebSocket frames correctly, leaving bytes in the InputBuffer until a subsequent message forces the reading code to finish what it started earlier. But I can't attest to that until I actually look at the code.
As Info: Another Test. If i send every second messages over a period of 1 minute, all arrive. If i now wait 20 seconds, an identical message does not arrive.
Ps.: If i deactivate the heartbeat, the problem also occurs.
My last Text was not correct. startHeartBeat starts a Thread which triggers the heartbeat-event...But the heartbeat itself, where can i found it?
Hi @Gregory667 You need to define the heartbeat event: https://github.com/arvanus/Indy/blob/4b2213573a15007a7a8cf767700a5ac5a6b5ee03/Lib/Core/IdWebSocketSimpleClient.pas#L537 If you hasn't defined the event then it's doing nothing Also do you have any exception in your server or client? Thanks
Now it works. I defined the Event and send a Ping to the server. I got no exceptions. But i assigned the onError event and react especially to forceDisconnect.
At the end of the dataevent i placed a TIdSimpleWebSocketClient(sender).Socket.InputBuffer.Clear;
I am able to connect to my websocket using TIdSimpleWebSocketClient. Any example code for how to read the data?
@arvanus
Hello, I am use this in a wss:// case in Android with Lib from OpenSSL, it is very odd that the text send out to server will always lost the last character, Such as, "HellO", the server receive only "Hell" .
But on windows, there is no problem. Only in Android FMX app will lost the last character, I also test this with another web-socket client from another Githuber, both has the same problem.
@rlebeau A bug from Indy socket with the Android implement?
Thanks
answering my own question above in case anyone ends up here. The class works perfectly to connect to a websocket built on indy (thanks @arvanus and @rlebeau ), all you need to get the data out is a procedure for example: procedure TForm1.OnWebSocketMessage(Sender: TObject; const Str: string); begin TThread.Synchronize(nil, procedure begin Memo1.Lines.Add(str); end); end; to be assigned to lSWC.onDataEvent := OnWebSocketMessage; I am sure there are better ways of doing this but this worked for me