views:

96

answers:

2

i am trying to send a picture from 'C:\picture.bmp' to 'c:\temp\picture.bmp' using server and client socket clients onconnect event handler is as follow:

procedure TForm2.ClientSocket1Connect(Sender: TObject;
  Socket: TCustomWinSocket);
 var
  fs : tfilestream;
  begin
     fs := TFileStream.create('C:\picture.bmp', fmOpenRead);//picture allready exists
     socket.SendStream(fs);
     fs.free;             
end;

and servers onclientread as :

procedure TForm2.ServerSocket1ClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
  fmm : tfilestream;
  iLen: Integer;
    Bfr: Pointer;
  begin

     iLen := Socket.ReceiveLength;
  GetMem(Bfr, iLen);
  fmm := TFileStream.Create('c:\temp\picture.bmp', fmCreate or 

fmShareDenyWrite);
  try
    Socket.ReceiveBuf(Bfr^, iLen);
    fmm.Write(Bfr^, iLen);
  finally
    FreeMem(Bfr);
    fmm.Free;
  end;

end;

picture is recieved/created but is either corrupt on was never recieved i.e created because of tfilestream.create method? please help!what am i doing wrong?

+1  A: 

I don't know what's wrong, but I'd try troubleshooting a simpler problem. i.e. can you even transfer somethign simple? See if you can transfer c:\hello.txt containing just "Hello" and have it arrive in the right order. It should be easier to examine the stream and resulting file, to see if/where things are getting garbled. If you don't receive "Hello" on the server, then you know it's got nothing to do with the size or complexity of the data.

Chris Thornton
thanks for the answer, yes i can transfer text files, jpeg's are giving me proplems PLEASE HELP!
Omair Iqbal
although text files i sent were pretty small
Omair Iqbal
Maybe try some large ones with a pattern so you can see if there are any gaps, transpositions, etc...
Chris Thornton
+1  A: 

Despite its name, SendStream() is NOT guaranteed to send the entire stream (especially if you are using a non-blocking socket). Its return value returns how many bytes are actually sent. If less than the full size of the stream are sent in one call, you have to call SendStream() again, potentially many times, to finish sending the entire stream (the same problems exists with SendText() as well).

On the other side, ReceiveLength() only reports how many bytes are available on the socket AT THAT MOMENT. That is likely to be less than the full stream being sent (likewise, ReceiveText() may not receive a full sent string either because it uses ReceiveLength() internally).

The best way to send a stream (or any arbitrary data in general) is to send the data's size first, then send the actual data afterwards. Keep calling SendBuf/Stream/Text() until that size is reached (if -1 is returned by a non-blocking socket without raising an exception, you have to wait for the socket's OnWrite event to trigger before the socket can accept more data again). On the receiving end, read the size first, then keep reading until the specified size is reached. You may have to read in multiple triggering of the OnRead event before you get all of the data.

Go to http://www.deja.com and http://forums.embarcadero.com to search the Borland/CodeGear/Embarcadero newsgroup/forum archives. I have posted example code many times before.

Remy Lebeau - TeamB
For instance https://forums.embarcadero.com/message.jspa?messageID=234664 and https://forums.embarcadero.com/message.jspa?messageID=255358--jeroen
Jeroen Pluimers
thanks for the answer,i dont know much about sockets which is better non-blocking or blocking?i still cant send it can you point to an other example than jeroen pluimers did or can you please modify my code to make it work? what do you mean by sendstream again and again, wont that send stream from start i mean i cant find any parameters like data.position(which we can set to current position) in socket.sendstream .... PLEASE HELP!
Omair Iqbal
'' Its return value returns how many bytes are actually sent'' does sendstream returns how many bytes have been send? isnt it that it returns only boolean values ie true/false after sending stream?
Omair Iqbal
@omair: My bad about the return value, SendStream() does indeed return a boolean. However, what I said about SendStream() not guaranteed to send the entire stream still applies. As soon as the socket reports any error, even WSAEWOULDBLOCK (which is likely if you try to send a large stream with a non-blocking socket), it stops sending and exits. The boolean return value is not very meaningful. It is False only if the socket was not connected when SendStream() was called. It always returns True otherwise, even if a send error occurs (in which situation, the OnError event will trigger)...
Remy Lebeau - TeamB
... SendStream() starts sending from the stream's current Position. So you can call SendStream() in a loop until the stream Position reaches the stream Size, SendStream() returns False, or an OnError event occurs, whichever comes first.
Remy Lebeau - TeamB
Personally, I would avoid SendStream() (and SendText()) altogether, and just use SendBuf() directly. That allows you to do a lot better error handling and status checking.
Remy Lebeau - TeamB
strange when i removed filestream.free method from both server side and client side i was able to sent complete file
Omair Iqbal
Obviously, that would not be a good idea, as you would then be leaving files open on both ends. As I mentioned before, please search the archives for detailed examples of how to safely send streams with TClientSocket/TServerSocket.
Remy Lebeau - TeamB