Solved

Socket: Sending Text

Posted on 2000-04-08
18
445 Views
Last Modified: 2010-04-04
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
Comment
Question by:dokken
  • 8
  • 6
  • 3
  • +1
18 Comments
 

Expert Comment

by:Portal
Comment Utility
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
 

Author Comment

by:dokken
Comment Utility
It gets caught in an endless loop between the repeat and until.
0
 
LVL 13

Expert Comment

by:Epsylon
Comment Utility
I suggest to send a zero (a so called sentinel) after the string so the receiver knows when to cut off...
0
 

Author Comment

by:dokken
Comment Utility
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
 
LVL 1

Expert Comment

by:DValery
Comment Utility
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
 

Author Comment

by:dokken
Comment Utility
DValery,

The text ends up being stored in the BDP array, right? how do I get it into a string?
0
 
LVL 1

Expert Comment

by:DValery
Comment Utility
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
 

Author Comment

by:dokken
Comment Utility
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
 
LVL 13

Expert Comment

by:Epsylon
Comment Utility
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
What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

 

Author Comment

by:dokken
Comment Utility
Epsylon,

Thanks... I'll take a look at it.
0
 

Author Comment

by:dokken
Comment Utility
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
 
LVL 1

Expert Comment

by:DValery
Comment Utility
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
 
LVL 13

Accepted Solution

by:
Epsylon earned 80 total points
Comment Utility
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
 

Author Comment

by:dokken
Comment Utility
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
 
LVL 1

Expert Comment

by:DValery
Comment Utility
dokken,
If you want, I can send my sample by email...
0
 

Author Comment

by:dokken
Comment Utility
DValery,

Is your sample for F. Piette Socket or Delphi 5's Socket?
0
 
LVL 1

Expert Comment

by:DValery
Comment Utility
As I did write, I use the F. Piette Socket or Delphi.
0
 
LVL 1

Expert Comment

by:DValery
Comment Utility
Sorry ;o)
As I did write, I use the F. Piette Socket.
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
In this tutorial you'll learn about bandwidth monitoring with flows and packet sniffing with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're interested in additional methods for monitoring bandwidt…
When you create an app prototype with Adobe XD, you can insert system screens -- sharing or Control Center, for example -- with just a few clicks. This video shows you how. You can take the full course on Experts Exchange at http://bit.ly/XDcourse.

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now