Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x
?
Solved

Socket: Sending Text

Posted on 2000-04-08
18
Medium Priority
?
454 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 8
  • 6
  • 3
  • +1
18 Comments
 

Expert Comment

by:Portal
ID: 2697373
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
ID: 2697678
It gets caught in an endless loop between the repeat and until.
0
 
LVL 13

Expert Comment

by:Epsylon
ID: 2697793
I suggest to send a zero (a so called sentinel) after the string so the receiver knows when to cut off...
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 

Author Comment

by:dokken
ID: 2697870
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
ID: 2697883
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
ID: 2697929
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
ID: 2697962
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
ID: 2698037
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
ID: 2698353
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
 

Author Comment

by:dokken
ID: 2698377
Epsylon,

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

Author Comment

by:dokken
ID: 2698590
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
ID: 2698971
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 240 total points
ID: 2699275
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
ID: 2701446
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
ID: 2702707
dokken,
If you want, I can send my sample by email...
0
 

Author Comment

by:dokken
ID: 2704161
DValery,

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

Expert Comment

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

Expert Comment

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

Featured Post

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
In this video, Percona Director of Solution Engineering Jon Tobin discusses the function and features of Percona Server for MongoDB. How Percona can help Percona can help you determine if Percona Server for MongoDB is the right solution for …
Is your data getting by on basic protection measures? In today’s climate of debilitating malware and ransomware—like WannaCry—that may not be enough. You need to establish more than basics, like a recovery plan that protects both data and endpoints.…
Suggested Courses

604 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