Page 1 of 2 12 LastLast
Results 1 to 10 of 18

Thread: String Manipulation and Networking Questions.

  1. #1

    String Manipulation and Networking Questions.

    Hello,

    I created a client and server Application in Delphi and am having a very serious problem.

    The client is sending a message to the server every 1 millisecond to see how the server performs and my server is supposed to respond with 'Response: Server recieved text.', and it does most of the time but sometimes it sends 'Response: Server recieved text.Response: Server recieved text.' in one line, which it shouldn't.

    Also, how do I read all the rest of the characters in a string EXCEPT the first 4 that are in the string?

    The application itself is about 600KB in size. But it is using 60 MB of memory.

    How can I make it free memory?

    Could someone please help me?

    Thank you.
    Nicholas.
    <br />
    <br />Please join: http://holzstukka.proboards81.com

  2. #2

    Re: String Manipulation and Networking Questions.

    Hello!

    Do you wait for the response from the server before you send him another package from the client?

    TCP Connections must be used like byte oriented streams and not packed oriented streams, because the IP packages can be fragmented from one host to another or are put together on the receivers side, if the receiver is too busy to handle each packet.

    That's the reason, why you get multiple messages in "one read".

    If client/server receives a message you have to do something like this
    Code:
    while DataAvailable do
      ReadOneMessage
    For the "ReadOneMessage" part you have to introduce some sort of internal packaging, like adding a special character at the of each messages (CR?) or start with a message len.

    Why do you want to dismiss the first 4 characters? Are they looking ugly? Then it may be the length (in Bytes) of the received message. Read the first 4 bytes as an 32bit Integer and then exactly the amount of characters for the message-data.

    For further help, simply post your code
    HTH

  3. #3

    String Manipulation and Networking Questions.

    Hi

    Yes....

    "
    unit Unit1;

    interface

    uses
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
    Dialogs, StdCtrls, XPMan, ScktComp, ExtCtrls;

    type
    TForm1 = class(TForm)
    CSOCK1: TClientSocket;
    XPManifest1: TXPManifest;
    Button1: TButton;
    MTXB1: TMemo;
    TXTS1: TMemo;
    Button2: TButton;
    SVATT1: TTimer;
    LBMSCOUNT2: TLabel;
    procedure SVATT1Timer(Sender: TObject);
    procedure CSOCK1Disconnect(Sender: TObject; Socket: TCustomWinSocket);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure CSOCK1Read(Sender: TObject; Socket: TCustomWinSocket);
    procedure CSOCK1Connect(Sender: TObject; Socket: TCustomWinSocket);
    private
    { Private declarations }
    public
    { Public declarations }
    end;

    var
    Form1: TForm1;
    MSCOUNT2: integer;
    VSOCKR2: string;

    implementation

    {$R *.dfm}

    procedure TForm1.Button1Click(Sender: TObject);
    begin
    CSOCK1.Active := true;
    end;

    procedure TForm1.Button2Click(Sender: TObject);
    begin
    CSOCK1.Socket.SendText(TXTS1.Text);
    TXTS1.Lines.Clear;
    end;

    procedure TForm1.CSOCK1Connect(Sender: TObject; Socket: TCustomWinSocket);
    begin
    MTXB1.Lines.Add('Connected to server');
    Socket.SendText('Client-Server connection successful');
    end;

    procedure TForm1.CSOCK1Disconnect(Sender: TObject; Socket: TCustomWinSocket);
    begin
    Windows.Beep(400, 100);
    MTXB1.Lines.Add('Disconnected');
    end;

    procedure TForm1.CSOCK1Read(Sender: TObject; Socket: TCustomWinSocket);
    begin
    VSOCKR2 := Socket.ReceiveText;
    if VSOCKR2 <> 'Response: Server recieved text.' then MTXB1.Lines.Add(VSOCKR2);
    if VSOCKR2 = 'Response: Server recieved text.' then
    begin
    MSCOUNT2 := MSCOUNT2 + 1;
    LBMSCOUNT2.Caption := IntToStr(MSCOUNT2);
    end;
    if VSOCKR2 = 'PING' then Socket.SendText(VSOCKR2);

    end;

    procedure TForm1.SVATT1Timer(Sender: TObject);
    begin
    if VSOCKR2 = 'Response: Server recieved text.' then
    begin
    if CSOCK1.Socket.Connected = true then CSOCK1.Socket.SendText('Testing server...');
    end;

    end;

    end."

    That's the modified code,, so now it still sends two on the same line.

    It stops.

    How can I fix that?

    Sloppy, I know.

    Disregard the unessecary parts like the PING part, which is a mistake.

    The client sends a message, and then the server replies to each message with "Response: Server recieved text.". Then it goes on like that.

    But the problem, is that sometimes when it's going really fast I see "Response: Server recieved text.Response: Server recieved text."

    What do I do?

    I understand what you're saying;
    Nicholas.
    <br />
    <br />Please join: http://holzstukka.proboards81.com

  4. #4

    String Manipulation and Networking Questions.

    Hello again!

    Code:
    procedure TForm1.CSOCK1Read&#40;Sender&#58; TObject; Socket&#58;TCustomWinSocket&#41;;
    begin
      VSOCKR2 &#58;= Socket.ReceiveText;
      if VSOCKR2 <> 'Response&#58; Server recieved text.' then MTXB1.Lines.Add&#40;VSOCKR2&#41;;
      if VSOCKR2 = 'Response&#58; Server recieved text.' then
      begin
        MSCOUNT2 &#58;= MSCOUNT2 + 1;
        LBMSCOUNT2.Caption &#58;= IntToStr&#40;MSCOUNT2&#41;;
      end;
    end;
    
    procedure TForm1.SVATT1Timer&#40;Sender&#58; TObject&#41;;
    begin
      if VSOCKR2 = 'Response&#58; Server recieved text.' then
      begin
        if CSOCK1.Socket.Connected = true then CSOCK1.Socket.SendText&#40;'Testing server...'&#41;;
       end;
    end;
    The problemtic code is the timer.
    If the value in VSOCKR2 is not "Response:..." no new messages are sent to the server. Because no new messages are sent to the server, your app don't receive a response and the value in VSOCKR2 will remain incorret.
    Therefore it will stop sending.
    On the other side, if the value in VSOCKR2 is correct, you send a message to your server and you don't reset the value to VSOCKR2 to ''. This means that VSOCKR2 is still correct, even if you don't have received any response from the server.

    I am going to post my own code example later.

    HTH

  5. #5

    String Manipulation and Networking Questions.

    The project-file:
    [pascal]
    program Project1;

    uses
    Forms,
    Unit1 in 'Unit1.pas' {Form1};

    {$R *.res}

    begin
    Application.Initialize;
    Application.CreateForm(TForm1, Form1);
    Application.Run;
    end.
    [/pascal]

    The Form:
    [pascal]
    object Form1: TForm1
    Left = 221
    Top = 134
    Width = 747
    Height = 485
    Caption = 'Form1'
    Color = clBtnFace
    Font.Charset = DEFAULT_CHARSET
    Font.Color = clWindowText
    Font.Height = -11
    Font.Name = 'MS Sans Serif'
    Font.Style = []
    OldCreateOrder = False
    OnCreate = FormCreate
    PixelsPerInch = 96
    TextHeight = 13
    object Label1: TLabel
    Left = 232
    Top = 16
    Width = 32
    Height = 13
    Caption = 'Label1'
    end
    object ClientBtn: TButton
    Left = 16
    Top = 8
    Width = 75
    Height = 25
    Caption = 'ClientBtn'
    TabOrder = 0
    OnClick = ClientBtnClick
    end
    object ClientLog: TListBox
    Left = 16
    Top = 40
    Width = 353
    Height = 393
    ItemHeight = 13
    TabOrder = 1
    end
    object ServerLog: TListBox
    Left = 384
    Top = 40
    Width = 337
    Height = 393
    ItemHeight = 13
    TabOrder = 2
    end
    object ServerBtn: TButton
    Left = 384
    Top = 8
    Width = 75
    Height = 25
    Caption = 'ServerBtn'
    TabOrder = 3
    OnClick = ServerBtnClick
    end
    object ClientSocket: TClientSocket
    Active = False
    ClientType = ctNonBlocking
    Host = 'localhost'
    Port = 2018
    OnLookup = ClientSocketLookup
    OnConnecting = ClientSocketConnecting
    OnConnect = ClientSocketConnect
    OnDisconnect = ClientSocketDisconnect
    OnRead = ClientSocketRead
    OnWrite = ClientSocketWrite
    OnError = ClientSocketError
    Left = 104
    Top = 8
    end
    object ServerSocket: TServerSocket
    Active = False
    Port = 2018
    ServerType = stNonBlocking
    OnListen = ServerSocketListen
    OnAccept = ServerSocketAccept
    OnGetThread = ServerSocketGetThread
    OnGetSocket = ServerSocketGetSocket
    OnThreadStart = ServerSocketThreadStart
    OnThreadEnd = ServerSocketThreadEnd
    OnClientConnect = ServerSocketClientConnect
    OnClientDisconnect = ServerSocketClientDisconnect
    OnClientRead = ServerSocketClientRead
    OnClientWrite = ServerSocketClientWrite
    OnClientError = ServerSocketClientError
    Left = 472
    Top = 8
    end
    object ClientTimer: TTimer
    Enabled = False
    Interval = 1
    OnTimer = ClientTimerTimer
    Left = 136
    Top = 8
    end
    object Timer1: TTimer
    OnTimer = Timer1Timer
    Left = 280
    Top = 8
    end
    end
    [/pascal]


    The Unit:
    [pascal]
    unit Unit1;

    interface

    uses
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
    Dialogs, StdCtrls, ScktComp, ExtCtrls;

    type
    TForm1 = class(TForm)
    ClientBtn: TButton;
    ClientLog: TListBox;
    ClientSocket: TClientSocket;
    ServerSocket: TServerSocket;
    ServerLog: TListBox;
    ServerBtn: TButton;
    ClientTimer: TTimer;
    Label1: TLabel;
    Timer1: TTimer;
    procedure ClientSocketConnect(Sender: TObject;
    Socket: TCustomWinSocket);
    procedure ClientSocketConnecting(Sender: TObject;
    Socket: TCustomWinSocket);
    procedure ClientSocketDisconnect(Sender: TObject;
    Socket: TCustomWinSocket);
    procedure ClientSocketError(Sender: TObject; Socket: TCustomWinSocket;
    ErrorEvent: TErrorEvent; var ErrorCode: Integer);
    procedure ClientSocketLookup(Sender: TObject;
    Socket: TCustomWinSocket);
    procedure ClientSocketRead(Sender: TObject; Socket: TCustomWinSocket);
    procedure ClientSocketWrite(Sender: TObject; Socket: TCustomWinSocket);
    procedure ClientBtnClick(Sender: TObject);
    procedure ServerBtnClick(Sender: TObject);
    procedure ServerSocketAccept(Sender: TObject;
    Socket: TCustomWinSocket);
    procedure ServerSocketClientConnect(Sender: TObject;
    Socket: TCustomWinSocket);
    procedure ServerSocketClientDisconnect(Sender: TObject;
    Socket: TCustomWinSocket);
    procedure ServerSocketClientError(Sender: TObject;
    Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
    var ErrorCode: Integer);
    procedure ServerSocketGetSocket(Sender: TObject; Socket: Integer;
    var ClientSocket: TServerClientWinSocket);
    procedure ServerSocketGetThread(Sender: TObject;
    ClientSocket: TServerClientWinSocket;
    var SocketThread: TServerClientThread);
    procedure ServerSocketListen(Sender: TObject;
    Socket: TCustomWinSocket);
    procedure ServerSocketThreadEnd(Sender: TObject;
    Thread: TServerClientThread);
    procedure ServerSocketThreadStart(Sender: TObject;
    Thread: TServerClientThread);
    procedure ClientTimerTimer(Sender: TObject);
    procedure ServerSocketClientRead(Sender: TObject;
    Socket: TCustomWinSocket);
    procedure ServerSocketClientWrite(Sender: TObject;
    Socket: TCustomWinSocket);
    procedure FormCreate(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);

    { Private-Deklarationen }
    public
    { Public-Deklarationen }
    ServerRecvBuf,
    ClientRecvBuf : String;
    Packets : Integer;
    end;

    var
    Form1: TForm1;

    implementation

    {$R *.dfm}

    procedure TForm1.ClientSocketConnect(Sender: TObject;
    Socket: TCustomWinSocket);
    begin
    ClientLog.Items.Add('Connect '+
    Socket.RemoteAddress+' '+
    IntToStr(Socket.RemotePort));
    end;

    procedure TForm1.ClientSocketConnecting(Sender: TObject;
    Socket: TCustomWinSocket);
    begin
    ClientLog.Items.Add('Connecting '+
    Socket.RemoteAddress+' '+
    IntToStr(Socket.RemotePort));
    end;

    procedure TForm1.ClientSocketDisconnect(Sender: TObject;
    Socket: TCustomWinSocket);
    begin
    ClientLog.Items.Add('Disconnect '+
    Socket.RemoteAddress+' '+
    IntToStr(Socket.RemotePort));
    end;

    procedure TForm1.ClientSocketError(Sender: TObject;
    Socket: TCustomWinSocket;
    ErrorEvent: TErrorEvent;
    var ErrorCode: Integer);
    begin
    ClientLog.Items.Add('Error '+
    Socket.RemoteAddress+' '+
    IntToStr(Socket.RemotePort)+' '+
    IntToStr(ErrorCode));
    end;

    procedure TForm1.ClientSocketLookup(Sender: TObject;
    Socket: TCustomWinSocket);
    begin
    ClientLog.Items.Add('LookUp '+
    Socket.RemoteAddress+' '+
    IntToStr(Socket.RemotePort));
    end;

    procedure TForm1.ClientBtnClick(Sender: TObject);
    begin
    ClientSocket.Active := not ClientSocket.Active;
    ClientTimer.Enabled := not ClientTimer.Enabled;
    end;

    procedure TForm1.ServerBtnClick(Sender: TObject);
    begin
    ServerSocket.Active := not ServerSocket.Active;
    end;

    procedure TForm1.ServerSocketAccept(Sender: TObject;
    Socket: TCustomWinSocket);
    begin
    ServerLog.Items.Add('Accept '+
    Socket.RemoteAddress+' '+
    IntToStr(Socket.RemotePort));
    end;

    procedure TForm1.ServerSocketClientConnect(Sender: TObject;
    Socket: TCustomWinSocket);
    begin
    ServerLog.Items.Add('Connect '+
    Socket.RemoteAddress+' '+
    IntToStr(Socket.RemotePort));

    end;

    procedure TForm1.ServerSocketClientDisconnect(Sender: TObject;
    Socket: TCustomWinSocket);
    begin
    ServerLog.Items.Add('Disconnect '+
    Socket.RemoteAddress+' '+
    IntToStr(Socket.RemotePort));
    end;

    procedure TForm1.ServerSocketClientError(Sender: TObject;
    Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
    var ErrorCode: Integer);
    begin
    ServerLog.Items.Add('Error '+
    Socket.RemoteAddress+' '+
    IntToStr(Socket.RemotePort)+' '+
    IntToStr(ErrorCode));
    end;

    procedure TForm1.ServerSocketGetSocket(Sender: TObject; Socket: Integer;
    var ClientSocket: TServerClientWinSocket);
    begin
    if Assigned(ClientSocket) then
    ServerLog.Items.Add('GetSocket '+
    ClientSocket.RemoteAddress+' '+
    IntToStr(ClientSocket.RemotePort))
    else
    ServerLog.Items.Add('GetSocket');

    end;

    procedure TForm1.ServerSocketGetThread(Sender: TObject;
    ClientSocket: TServerClientWinSocket;
    var SocketThread: TServerClientThread);
    begin
    if Assigned(SocketThread) then
    ServerLog.Items.Add('GetThread '+
    ClientSocket.RemoteAddress+' '+
    IntToStr(ClientSocket.RemotePort)+' '+
    IntToStr(SocketThread.Handle))
    else
    ServerLog.Items.Add('GetThread '+
    ClientSocket.RemoteAddress+' '+
    IntToStr(ClientSocket.RemotePort));
    end;

    procedure TForm1.ServerSocketListen(Sender: TObject;
    Socket: TCustomWinSocket);
    begin
    ServerLog.Items.Add('Listen '+
    Socket.LocalAddress+' '+
    IntToStr(Socket.LocalPort));
    end;

    procedure TForm1.ServerSocketThreadEnd(Sender: TObject;
    Thread: TServerClientThread);
    begin
    ServerLog.Items.Add('EndThread '+
    IntToStr(Thread.Handle));
    end;

    procedure TForm1.ServerSocketThreadStart(Sender: TObject;
    Thread: TServerClientThread);
    begin
    ServerLog.Items.Add('StartThread '+
    IntToStr(Thread.Handle));
    end;

    //------------------------------------------

    procedure TForm1.ClientTimerTimer(Sender: TObject);
    begin
    //Send the message. Use the #13 (CR) as Message separator
    ClientSocket.Socket.SendText('MyText'#13);
    end;

    procedure TForm1.ClientSocketRead(Sender: TObject;
    Socket: TCustomWinSocket);
    var
    Data : String;
    iPos : Integer;
    //iCount : Integer;
    begin
    //Receive the whole buffer
    ClientRecvBuf := ClientRecvBuf + Socket.ReceiveText;

    //Read messages till buffer is empty
    //iCount:=1;
    repeat
    iPos := 1;
    while iPos<length(ClientRecvBuf) do
    begin
    //Check for seperator char
    if ClientRecvBuf[iPos]=#13 then break;
    inc(iPos);
    end;

    Data := Copy(ClientRecvBuf,1,iPos-1);
    Delete(ClientRecvBuf,1,iPos);
    {
    ClientLog.Items.Add('Read '+IntToStr(iCount)+' '+
    Socket.RemoteAddress+' '+
    IntToStr(Socket.RemotePort)+' '+
    Data);
    inc(iCount);
    }
    inc(Packets);

    until ClientRecvBuf='';
    end;

    procedure TForm1.ClientSocketWrite(Sender: TObject;
    Socket: TCustomWinSocket);
    begin
    {
    ClientLog.Items.Add('Write '+
    Socket.RemoteAddress+' '+
    IntToStr(Socket.RemotePort));
    }
    end;

    procedure TForm1.ServerSocketClientRead(Sender: TObject;
    Socket: TCustomWinSocket);
    var
    Data : String;
    iPos : Integer;
    begin
    //Receive the whole buffer
    ServerRecvBuf := ServerRecvBuf + Socket.ReceiveText;

    //Read messages till buffer is empty
    repeat
    iPos := 1;
    while iPos<length(ServerRecvBuf) do
    begin
    //Check for seperator char
    if ServerRecvBuf[iPos]=#13 then break;
    inc(iPos);
    end;

    //Only process data, if Message is complete (last char =#13)
    //This is alway true, as long as iPos is not byond the end
    //of the Buffer
    if iPos<=length(ServerRecvBuf) then
    begin
    Data := Copy(ServerRecvBuf,1,iPos-1);
    Delete(ServerRecvBuf,1,iPos);
    {
    ServerLog.Items.Add('Read '+
    Socket.RemoteAddress+' '+
    IntToStr(Socket.RemotePort)+' '+
    Data);
    }

    //Just for randomly generate multiple receives.
    If Random(100)=5
    then Socket.SendText('ReceivedText'#13'ReceivedText'#13 )
    else Socket.SendText('ReceivedText'#13);
    end;

    until ClientRecvBuf='';

    end;

    procedure TForm1.ServerSocketClientWrite(Sender: TObject;
    Socket: TCustomWinSocket);
    begin
    ServerLog.Items.Add('Write '+
    Socket.RemoteAddress+' '+
    IntToStr(Socket.RemotePort));
    end;

    procedure TForm1.FormCreate(Sender: TObject);
    begin
    Randomize;
    Packets := 0;
    end;

    procedure TForm1.Timer1Timer(Sender: TObject);
    begin
    Label1.Caption := IntToStr(Packets);
    end;

    end.
    [/pascal]

  6. #6

    String Manipulation and Networking Questions.

    The problem is that I don't want it to halt everything when there's an error, but I don't want it to generate that error in the first place...because if I just told it to stop, then i would end up losing thousands of messges and that would be really bad....

    thanks.
    Nicholas.
    <br />
    <br />Please join: http://holzstukka.proboards81.com

  7. #7

    String Manipulation and Networking Questions.

    What kind of error do you mean? From your app or from my testapp?

  8. #8

    String Manipulation and Networking Questions.

    You are using TCP for your connection. TCP can concatenate packets into one larger packet, so your code must be able to handle this. Usually this is done by inserting your own separators or a small header that tells the receiver the length of the packet. The receiver then reads the header or looks for the separators to be able to split the packets up into their original form.

    Having said that, commercial games use UDP for their networking because it does not suffer the overhead that TCP adds to a connection (ACKs, resends, etc).

  9. #9

    String Manipulation and Networking Questions.

    from my app

    the error is the repeating of that packet.
    Nicholas.
    <br />
    <br />Please join: http://holzstukka.proboards81.com

  10. #10

    String Manipulation and Networking Questions.

    My Testapp should give you an idea how to solve your problem. In my test-app I have implemented both, client AND server in one app. I also have added a lot of unnecessary eventhandlers for the client and the serversocket, which you do not need.

    In both cases the Read-Event should be enought + the timer to send messages to the server.

    Look especially to
    ClientSocketRead
    ServerSocketClientRead

    You can see, that I have added the #13 as the message-seperator. Don't bother with the Random(100)=5. This is for simply generate your behaviour and test the reaction of the client.

Page 1 of 2 12 LastLast

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •