Lindawb 0 Posted January 31, 2022 Hello, I just started using ICS, is there any way to use WSocket and send image as memory stream , if yes I really appreciate any help I get, I found few answers but I have no idea how to buffer and chunk or like that not a professional developer in this matter. I tried this  var  fstream: TMemoryStream;  MyFormJpeg, MyJpegImage: TJPEGImage; begin      MyFormJpeg := TJPEGImage.Create;    MyFormJpeg.CompressionQuality := 75;    MyFormJpeg.LoadFromFile('C:\temp\mycat.jpg');         fstream := TMemoryStream.Create;        try          MyFormJpeg.SaveToStream(fstream);        fstream.Position:= 0;         //WSocket1.BufSize:=fstream.Size;         WSocket1.Send(fstream, fstream.Size); // wsocket1.Send(MemStream.Memory, MemStream.Size); not working         //WSocket1.Send(PChar(fstream), fstream.Size * SizeOf(Char));               finally         fstream.Free;      MyJpegImage.Free;        end; also I can't find way to read on the server side, if possible to help  Thank you   Share this post Link to post
FPiette 382 Posted February 1, 2022 11 hours ago, Lindawb said: wsocket1.Send(MemStream.Memory, MemStream.Size); This is the way to send the content of the stream. But you have a problem for the receiver: how will the receiver know the length of the stream? It would be OK if this is the only thing sent for the whole session. Not a very good design. You should probably first send an integer with the stream size and then the stream content. The receiver will then first receive the length and then know how many byte it has to receive for the content. Â Also, you don't need to decode the JPEG before sending. Just load the file into the memory stream. The receiver will decode the JPEG. This will result in much less data sent thru the network. Â I don't know why you want to send the image using a bare socket. Bette to use a higher level component such as HTTP of FTP. Â Since you have not explained your whole problem, I cannot help you more. Â Share this post Link to post
Angus Robertson 574 Posted February 1, 2022 As François has said, to send binary files you should really be using a high level protocol like HTTP or FTP.  If you really want to invent your own protocol, you will save a lot of time and effort by using the newish TIcsIpStrmLog component that can be configured as a client or server, and is really a much easier to use version of WSocket. There is a sample application OverbyteIcsIpStmLogTst.dpr that has a local mode, where the sample runs as both a client and server sending and receiving lines of data to itself.  The component has a simple method SendStream that sends a stream of any size read from memory or a file, your earlier example with Send assume Windows can buffer your entire image, which will only work for smallish files. There is a onLogRecvEvent event that returns a string with received binary data you can write to a stream, but you will need to design a protocol to know the file name or type of data being received, it will be returned in variable sized chunks.  Angus  Share this post Link to post
Lindawb 0 Posted February 1, 2022 First thank you so much for your time and explanation, and sorry I didn't explain more, All I'm trying to do send screenshot to the server (admin) , I can't use FTP or HTTP, I'm trying to do screen share program kind of RDP. I thought if I understand how to send image I will do the rest, as I have code on how to capture scree and save to the MemStream Now I understand your point, I guess you mea something like this:   Client side: (Sender)        fstream := TMemoryStream.Create;        try         WSocket1.SendStr(inttostr(fstream.Size));         wsocket1.Send(fstream.Memory, fstream.Size);         finally          fstream.Free;        end;  Server (Receiver), as you said, I guess I have problem below.  procedure TTcpSrvForm.ClientDataAvailable(    Sender : TObject;    Error : Word); var    MyStream: TMemoryStream;    Buf : array [0..1024] of AnsiChar;    Len : Integer; begin     Len := TCustomLineWSocket(Sender).Receive(@Buf, Sizeof(Buf) - 1);    if Len <= 0 then        Exit;    Buf[Len] := #0;    MyStream := TMemoryStream.Create;    MyStream.WriteBuffer(Buf, Len);  end;  Thank you for any advice or suggestion.  Share this post Link to post
Fr0sT.Brutal 900 Posted February 1, 2022 Why not use HTTP here? I started some kind of this stuff and got it working but postponed for production. ICS HTTP server procedure TControlServer.ProcessRequest(Client: THttpConnectionEx; SendType: THttpSendType; var Flags: THttpGetFlag); begin ... if AppStatus.FormImg = nil then begin Client.AnswerHeader(Flags, HTTP_Status_204, HTTP_Type_TxtHtml, ''); Exit; end; Client.DocStream := TMemoryStream.Create; Client.DocStream.CopyFrom(AppStatus.FormImg, 0); Client.DocStream.Position := 0; Client.AnswerStream(Flags, HTTP_Status_200, 'image/bmp', Client.DoContentEncoding); end; ... enf; Bmp because screenshot is in bmp, just to not deal with encoding. With this code I got an image of main form available even in any browser Share this post Link to post
Lindawb 0 Posted February 1, 2022 (edited) I don't know if possible to use HTTP for RDP, client send screen, the admin send mouse and keyboard inputs , I'm just stuck with sending and reading TMemoryStream, Thank you for any advice or suggestion. Â Edited February 1, 2022 by Lindawb Share this post Link to post
qubits 20 Posted February 1, 2022 Buf should be an array of byte. Also should be big enough to grab your image and get rid of the additional #0. But like the other have pointed out, this will only work if it's all your sending. Really, you should make a packet header with a fixed known size that should at least let you know the size of the additional data to recv. Then, you just recv packet header, see data size and keep receiving unit you get it all.   i do something like this..  pPacketHdr=^tPacketHdr; tPacketHdr= packer record  Indent:array[0..15] of byte;//indentifier  Command:byte;  DataSize:integer; end;   i use tByteDynArray as my final buffer..  outBuff:tByteDynArray; TotalSize:=SizeOf(tPacketHdr)+MemStrm.Size; SetLength(outBuff,TotalSize); offSet:=0; Move(packetHdr,outBuff[offSet],SizeOf(tPacketHdr)); offSet:=offSet+SizeOf(tPacketHdr); then move the rest in..    first get the header with 0 data moving, then just add data, any data.. use command byte to tell you what your getting.. ident is unique to you and you can set and check it on every packet, if it doesn't match your ident ignore it.. Share this post Link to post
Lindawb 0 Posted February 1, 2022 Thank you so much for your time, I will work on this and try to understand how , where to use those and how to fill in as I said I'm not that good developer, but getting there 🙂 there are many good examples in ICS, but I can't find any stream example not even on the search engines. Thanks again for your time.  Share this post Link to post
qubits 20 Posted February 1, 2022 no worries, your close, just remember, it's not a string or anistring, it's bytes.  type  TMyClient = class(TWSocketThrdClient)  public    Buff       : array[0..9999999] of byte;    Count:integer;    ConnectTime : TDateTime;    ClearToSend :boolean;    GoodHeader :boolean;  end;   procedure TServerCommsDm.SocketDataAvailable(    Sender : TObject;    Error : Word); var    Cli : TMyClient;    Len:integer;    aPacketHdr:TPacketHdr; begin    Cli := Sender as TMyClient;    //recv bin data into our buffer..    Len:=Cli.Receive(@Cli.Buff[Cli.Count],SizeOf(Cli.Buff)-Cli.Count);    //did we get some!!    if Len <= 0 then        Exit;        //count it..        Cli.Count:=Cli.Count +Len;       //see if we got enough for a packet     if Cli.Count>=SizeOf(TPacketHdr) then        begin        Move(Cli.Buff,aPacketHdr,SizeOf(aPacketHdr));        if CheckIdent(aPacketHdr.PacketIdent) then         begin         Cli.GoodHeader:=true;         Display('Recvd Valid Header:DataSize='+IntToStr(aPacketHdr.DataSize));          //packets can have extra data.. check for a datasize..          if Cli.Count>=(aPacketHdr.DataSize+SizeOf(aPacketHdr)) then           begin            Display('Received packet from ' + Cli.GetPeerAddr);            ProcessData(Cli);           end;         end else            begin              Cli.GoodHeader:=false;              Display('Received bad header from '+Cli.GetPeerAddr);              Cli.Count:=0;//start it all again              FillChar(Cli.Buff,SizeOf(Cli.Buff),#0);//zero the buffer            end;        end; end;    Share this post Link to post
Lindawb 0 Posted February 1, 2022 Thank you so much, I really appreciate your time and support, without people like you new developers never learn :) you all awesome! any idea where is TWSocketThrdClient located on which uint ?  Thanks again Share this post Link to post
qubits 20 Posted February 1, 2022 Winapi.Windows, Winapi.Messages,System.Types,System.SysUtils, System.Classes, System.SyncObjs, OverbyteIcsWndControl, OverbyteIcsWSocket,OverbyteIcsWSocketS, OverbyteIcsWSocketTS, OverbyteIcsUtils;  in one of these units.. 🙂 Share this post Link to post
qubits 20 Posted February 1, 2022 i was using the threaded server, you can probably omit the Thrd and try TWSocketClient, pretty sure it works the same just not threaded.. Share this post Link to post
Angus Robertson 574 Posted February 1, 2022 The onDataAvailable event is called repeated as more data arrives, you need to keep adding data to the receive stream until the connection is closed or your protocol signals the stream has received all that intended (why there are headers in HTTP).   TWSocketThrdClient and TWSocketClient relate to ICS server components and won't help in this case.  Angus  Share this post Link to post
qubits 20 Posted February 1, 2022 yep, and keeps adding to the client buffer and updates count, once all is recvd i processes it. works well for me.. sorry.. Share this post Link to post
Fr0sT.Brutal 900 Posted February 2, 2022 I still recommend HTTP. You'll have to invent your own protocol anyway so why not use already implemented one. Low-level Data events and buffer plays will be hidden from you by higher level events and classes. Share this post Link to post
Lindawb 0 Posted February 2, 2022 Thank you all, I'm not that processional developer in Delphi , I thought may be someone can help me with piece of code send and receive stream, I'm kind of show-me developer :( I will keep searching hope will find it Thanks to all of you. Share this post Link to post
qubits 20 Posted February 3, 2022 Yes, it's a bit tricky and Rome was not built in a day.. 🙂 thought we be sending jpegs..  but you should be able to bend this to your will..  Custom Packets  Good Luck! Share this post Link to post
Lindawb 0 Posted February 3, 2022 (edited) Thank you so much, I really appreciate your time and help, Â Thank you again Edited February 3, 2022 by Lindawb Share this post Link to post
qubits 20 Posted February 3, 2022 compiled with berlin 10.1 and ics version 8.62 Revised: August 6, 2019. i used Getit inside berlin to download the ics. try the latest version. Share this post Link to post
Lindawb 0 Posted February 3, 2022 You guys are awesome, thanks to all of you , especially qubits posting the complete code, I found latest ICS, installed and your example worked like charm :) Thank you all again. Share this post Link to post
qubits 20 Posted February 5, 2022 You're welcome, was a nice break from my robot wars. Which by the way, I used the demo ics packet server to test my cross platform packet client. Put a working demo of this up, should also compile for Berlin. Does the same, but pic recv is used as texture for cube which you can spin around, so it's like cooler. 🙂 TJpegImage doesn't exist in FMX, this shows how to save a jpeg stream.  Caution, did demo in my crazy 3d world, looking at the code too long may have adverse side affects. robots-ics  have fun! ~q   Share this post Link to post