Improve company productivity with a Business Account.Sign Up

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 460
  • Last Modified:

Socket: Sending Text

I'm using F. Piette TWSocket and I need to send text from the client to the server and vise versa.  The text can sometimes become large.  I've noticed that the text seems to get cut off when I used the sendstr().  I need some simple code that will send and receive all of the text.
0
dokken
Asked:
dokken
  • 8
  • 6
  • 3
  • +1
1 Solution
 
PortalCommented:
I assume you are using a memo edit box for the text. First save the text to a stream.
   var s : TMemoryStream;
   memo.lines.saveToStream(s);

Then Using your TWSocket send the message:

   serverSock.send(s.memory,s.size);

Then in the Client Sockets DataAvailable Event:
   
   var buffer : array[0..100] of byte;
       s : String;
   repeat
   count := clientSock.Receive(@buffer[0],100);
   s := '';
   for i := 0 to count - 1 do
      s := s + chr(buffer(i));
   until count = 0;
   {Add the string s to your clients output screen}

Maybe not the most elegant code but it is simple.
0
 
dokkenAuthor Commented:
It gets caught in an endless loop between the repeat and until.
0
 
EpsylonCommented:
I suggest to send a zero (a so called sentinel) after the string so the receiver knows when to cut off...
0
Upgrade your Question Security!

Your question, your audience. Choose who sees your identity—and your question—with question security.

 
dokkenAuthor Commented:
Epsylon,

I had found some code yesterday that was supposed to work doing it that way but it didn't.

I wonder if the client socket that came with Delphi can send the whole thing without a problem.
0
 
DValeryCommented:
Hi, dokken
I did use Piette's TWSocket in my project, here is a piece from my project



type
    TDPacket  = record          // Data packet
            Marker       : Byte;    //  Marker
             Length       : Integer  // Length of packet
    end;
    PDPacket     = ^TDPacket;

Const
      iFirstPak = 255;

var iLenRec : integer;      // Length of reciving packet of data
      iLength : integer;      // Length of sending data
      BDP         : array of Byte; // Packet of data

//            Initialize var:
//      iLenRec := 0;
//      iLength := 0;


procedure TForm1.CliSocketDataAvailable(Sender: TObject; Error: Word);
var s                  : string;
    iLenBuf         : integer;
    DPacket     : PDPacket;
begin
   iLenBuf := TWSocket(Sender).RcvdCount;
   if iLenBuf = 0 then Exit;
   try // except
     if iLenRec > 0 then begin // continues data packet
       SetLength(BDP, iLenBuf+iLenRec);
       TWSocket(Sender).Receive(@BDP[iLenRec], iLenBuf);      // Append data into buffer
       if iLenBuf+iLenRec < iLength+SizeOf(TDPacket) then begin
            iLenRec := iLenRec + iLenBuf;      
            Exit;      // Wait for next block data
         end
       else iLenBuf := iLenRec + iLenBuf;      // Recieved all the data
     end else begin // if iLenRec = 0 First packet
       SetLength(BDP, iLenBuf);
       TWSocket(Sender).Receive(@BDP[0], iLenBuf);  // Load first data in buffer
       iLenRec := iLenBuf;
       iLength := 0;
     end; // else if iLenRec > 0 then
     DPacket := @BDP[0];      // Pointer to Data packet
   except
   on E: Exception Do
    Begin
     Exit;
    end;
   end;

   if (iLength = 0) and (DPacket^.Marker = iFirstPak) then begin // First data packet
      iLength := DPacket^.Length;    // Length of sending data
      if iLenBuf < iLength+SizeOf(TDPacket) then begin
         iLenRec := iLenBuf;
         Exit;
      end;
      //
      // .....  Here you are having All data in BDP[3..(iLength+3)]
      //
      iLenRec := 0;
      iLength := 0;
   end else begin   // Next data packet
      if iLenBuf < iLength+SizeOf(TDPacket) then begin
         iLenRec := iLenBuf;
         Exit;
      end;
      //
      // .....  Here you are having All data in BDP[3..(iLength+3)]
      //
      iLenRec := 0;
      iLength := 0;
   end; // else
end;

0
 
dokkenAuthor Commented:
DValery,

The text ends up being stored in the BDP array, right? how do I get it into a string?
0
 
DValeryCommented:
Hi, dokken
I'm correcting my answer:

type
    TDPacket  = record          // Data packet
            Marker       : Byte;    //  Marker
             Length       : Integer  // Length of packet
    end;
    PDPacket     = ^TDPacket;

Const
      iFirstPak = 255;

var iLenRec : integer;      // Length of reciving packet of data
      iLength : integer;      // Length of sending data
      BDP         : array of Byte; // Packet of data

//            Initialize var:
//      iLenRec := 0;
//      iLength := 0;


procedure TDM.CliSocketDataAvailable(Sender: TObject; Error: Word);
var s                  : string;
    iLenBuf         : integer;
    DPacket     : PDPacket;
begin
   iLenBuf := TWSocket(Sender).RcvdCount;
   if iLenBuf = 0 then Exit;
   try // except
     if iLenRec > 0 then begin // continues data packet
       SetLength(BDP, iLenBuf+iLenRec);
       TWSocket(Sender).Receive(@BDP[iLenRec], iLenBuf);      // Append data into buffer
       if iLenBuf+iLenRec < iLength+SizeOf(TDPacket) then begin
            iLenRec := iLenRec + iLenBuf;      
            Exit;      // Wait for next block data
         end
       else iLenBuf := iLenRec + iLenBuf;      // Recieved all the data
     end else begin // if iLenRec = 0 First packet
       SetLength(BDP, iLenBuf);
       TWSocket(Sender).Receive(@BDP[0], iLenBuf);  // Load first data in buffer
       iLenRec := iLenBuf;
       iLength := 0;
     end; // else if iLenRec > 0 then
     DPacket := @BDP[0];      // Pointer to Data packet
   except
   on E: Exception Do
    Begin
     Exit;
    end;
   end;

   if (iLength = 0) and (DPacket^.Marker = iFirstPak) then begin // First data packet
      iLength := DPacket^.Length;    // Length of sending data
      if iLenBuf < iLength+SizeOf(TDPacket) then begin
         iLenRec := iLenBuf;
         Exit;
      end;
      //
      // .....  Here you are having All data in BDP[3..(iLength+3)]
      // Like:
        //              Memo2.Lines.SetText(PChar(BDP[SizeOf(TDPacket)]));
      //
      iLenRec := 0;
      iLength := 0;
   end else begin   // Next data packet
      if iLenBuf < iLength+SizeOf(TDPacket) then begin
         iLenRec := iLenBuf;
         Exit;
      end;
      //
      // .....  Here you are having All data in BDP[3..(iLength+3)]
      // Like:
        //              Memo2.Lines.SetText(PChar(BDP[SizeOf(TDPacket)]));
      //
      iLenRec := 0;
      iLength := 0;
   end; // else
end;


// For Sending application you have to make like here

type
    TDPacket  = record          // Data packet
            Marker       : Byte;    //  Marker
             Length       : Integer  // Length of packet
    end;
    PDPacket     = ^TDPacket;

Const
      iFirstPak = 255;

var BDPO         : array of Byte; // Packet of Send data

procedure TForm2.SendData;
Var
    SPacket   : PDPacket;
begin      
      SetLength(BDPO, Length(Memo1.Text)+SizeOf(TDPacket));
      SPacket := @BDPO[0];
         SPacket^.Marker := iFirstPak;
         SPacket^.Length := Length(Memo1.Text);      // Length of Text in memo
         Move(Memo1.Lines.GetText^,BDPO[SizeOf(TDPacket)], SPacket^.Length);
         TWSocket(Sender).Send(@SPacket,SPacket.Length+SizeOf(TDPacket));
end;

0
 
dokkenAuthor Commented:
DValery,

I changed the code like you have shown (including the send part), but for some reason I get an Access Violation at the second:
Memo2.Lines.SetText(PChar(BDP[SizeOf(TDPacket)]));

I do have a TMemo named Memo2 on the form. Any idea why I'm getting the AV?
0
 
EpsylonCommented:
Dokken, the TCP/IP components of Delphi work OK. At least in D4 and D5.

You can try this demo:

http://www5.ewebcity.com/epsylon/download.asp?file=RelayChat.zip

but when you want to send large strings you can send the entire content of a memo like this:

ClientSocket1.Socket.SendText(Memo1.Text);

Eps.
0
 
dokkenAuthor Commented:
Epsylon,

Thanks... I'll take a look at it.
0
 
dokkenAuthor Commented:
Epsylon,

Yep, that sends all of the text.  I've been converting my two programs (server & client) to use the components that came with Delphi so I can make sure your answer will help me.  It looks good so far, but two things have come up:

1. When the server responds to a message received from a client (there will be more than one client), how can I send a message back to the correct client? I haven't been able to figure out what exactly goes in the: Server.Socket.Connections[].SendText('my string here') part.  I can use 0 for testing, but it obviously won't work properly with multiple connections.

2. I need the IP address of the client connected to the server.  I know I can get it by using: Socket.RemoteAddr, but I don't know how to get the IP address out of that and into a string.

I'll give you the points if you can give me the answers to the two items above.



0
 
DValeryCommented:
Hi, dokken

Try it for copy text from buffer to memo:

blStream := TMemoryStream.Create;
try
 blStream.SetSize(iLength);
 Move(BDP[SizeOf(TDPacket)],blStream.Memory^, iLength);
 Memo2.Lines.LoadFromStream(blStream);
finally
 blStream.Free;
end;
0
 
EpsylonCommented:
1. In the OnClientRead event you can use the Socket parameter to send some text back:

procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var s: String;
begin
  s := Socket.ReceiveText;
  Socket.SendText('You sent me: ' + s);
end;


You can also send the received text to all connected clients except the sender:

procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var s: String;
    i: Integer;
begin
  s := Socket.ReceiveText;
  for i := 0 to ServerSocket1.Socket.ActiveConnections -1 do
    if Socket <> ServerSocket1.Socket.Connections[i] then
      ServerSocket1.Socket.Connections[i].SendText(s);
end;


2. Use Socket.RemoteAddress instead of Socket.RemoteAddr


Cheers,

Epsylon.
0
 
dokkenAuthor Commented:
Epsylon,

I don't know how I missed the RemoteAddress.

The only bad part about switching to this component is I've lost the threading that I was using.  I had code for the other component, but I haven't been able to get it to work properly with this component.  I really don't have any experience with threading, so I'll be asking about that once I buy some points.

Thanks for the help.
0
 
DValeryCommented:
dokken,
If you want, I can send my sample by email...
0
 
dokkenAuthor Commented:
DValery,

Is your sample for F. Piette Socket or Delphi 5's Socket?
0
 
DValeryCommented:
As I did write, I use the F. Piette Socket or Delphi.
0
 
DValeryCommented:
Sorry ;o)
As I did write, I use the F. Piette Socket.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

  • 8
  • 6
  • 3
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now