[Delphi6] IdTCPClient.ReadBuffer wil niet goed

Pagina: 1
Acties:
  • 435 views sinds 30-01-2008
  • Reageer

  • Osiris
  • Registratie: Januari 2000
  • Niet online
Ik ben al een tijdje bezig met een eigen MSN-Client maken enzo en dat wil op zich prima... Inloggen etc wil prachtig en is nix mis mee.

Maar zodra ik dus berichten wil ontvangen loop ik tegen het volgende probleem aan:
Het MSN-protocol mist aan het einde van een bericht een \r\n (of alleen \n, whatevah).

En ik werk met IdTCPClient.ReadLn('',5); Die wacht dus op een \r\n, die hij dus nooit zal krijgen... (nou ja, pas zodra er weer iets anders verstuurt wordt).

De laatste zin komt dus niet aan...

Dus dacht ik: Okay, ReadLn, logisch dat dat niet wil, want die wacht op een \r\n... Dus laten we ReadBuffer gebruiken!!!

Maar zodra ik die gebruik, wordt mijn applicatie opeens heel erg sloom? Ik snap dr nix van :/

Google geeft maar 2 links aan waar ik nix aan heb ([google=readbuffer idtcpclient]) en de help in Delphi zelf is ook totaal niet nuttig :X

Wie weet hoe je correct met Readbuffer om moet gaan?

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 23:27

Creepy

Tactical Espionage Splatterer

Is het niet zo dat readbuffer blijft wachten totdat het aantal opgegeven bytes zijn ingelezen?
Is er geen buffercount o.i.d zodat je weet hoeveel bytes er gelezen kunnen worden zonder dat je moet wachten op bytes die nog moeten komen?

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


  • Osiris
  • Registratie: Januari 2000
  • Niet online
Creepy schreef op 12 January 2003 @ 16:26:
Is het niet zo dat readbuffer blijft wachten totdat het aantal opgegeven bytes zijn ingelezen?
Is er geen buffercount o.i.d zodat je weet hoeveel bytes er gelezen kunnen worden zonder dat je moet wachten op bytes die nog moeten komen?
Zoiets bedoel je?:
Delphi:
1
2
3
4
5
6
7
8
9
procedure TForm1.Timer1Timer(Sender: TObject);
var msg:string;
begin
  If IdTCPClient1.CurrentReadBufferSize > 0 then
  begin
    msg := IdTCPClient1.CurrentReadBuffer;
    Memo1.Lines.Add(msg);
  end;
end;

[ Voor 3% gewijzigd door Osiris op 12-01-2003 21:23 ]


Verwijderd

Ik gebruik zelf ook de Indy TCP Client bij bepaalde Client/Server apps en ik set de timeout op 1 sec (moet wellicht in internet-omgeving hoger ivm bandbreedte) en daar bouw ik het volgende :

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
procedure TForm1.Timer1Timer(Sender: TObject);
var
s: string;
begin
  if not idTCPClient1.Connected then exit; {if not connected then exit}
 
 try
  s:=idTcpClient1.ReadLn();
  listbox1.Items.add(s); {add message to listbox}
  except
    exit;
    end;
end;

Dit werkt over het algemeen prima :7

  • Osiris
  • Registratie: Januari 2000
  • Niet online
Verwijderd schreef op 12 januari 2003 @ 21:23:
Ik gebruik zelf ook de Indy TCP Client bij bepaalde Client/Server apps en ik set de timeout op 1 sec (moet wellicht in internet-omgeving hoger ivm bandbreedte) en daar bouw ik het volgende :

Dit werkt over het algemeen prima :7
Maar als je eventjes goed gelezen had, dan zag je, dat er als laatste geen \r\n verstuurt wordt en ik dus ook niets aan ReadLn heb, aangezien die op een \r\n wacht...

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 23:27

Creepy

Tactical Espionage Splatterer

Osiris schreef op 12 January 2003 @ 21:18:
[...]

Zoiets bedoel je?:
Delphi:
1
2
3
4
5
6
7
8
9
procedure TForm1.Timer1Timer(Sender: TObject);
var msg:string;
begin
  If IdTCPClient1.CurrentReadBufferSize > 0 then
  begin
    msg := IdTCPClient1.CurrentReadBuffer;
    Memo1.Lines.Add(msg);
  end;
end;
Ja, alleen dan m.b.v. readbuffer met als parameter voor het aantal te lezen bytes het aantal bytes op het moment in de buffer, zodat je precies evenveel bytes leest als dat er al in de buffer staan (idtcpclient1.readbuffer(buf,idtcpclient1.buffersize)).

Ik heb echter hier geen Delphi bij de hand dus ik heb geen idee of het klopt, maar ik kan me zoiets herinneren.

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


  • Osiris
  • Registratie: Januari 2000
  • Niet online
Creepy schreef op 12 January 2003 @ 21:25:
[...]

Ja, alleen dan m.b.v. readbuffer met als parameter voor het aantal te lezen bytes het aantal bytes op het moment in de buffer, zodat je precies evenveel bytes leest als dat er al in de buffer staan (idtcpclient1.readbuffer(buf,idtcpclient1.buffersize)).

Ik heb echter hier geen Delphi bij de hand dus ik heb geen idee of het klopt, maar ik kan me zoiets herinneren.
Hmz, mjah, maar waarom ditte nix geeft vind ik vreemd.. Ff-tjes die manier proberen dan :)

Verwijderd

Osiris schreef op 12 januari 2003 @ 21:24:
[...]

Maar als je eventjes goed gelezen had, dan zag je, dat er als laatste geen \r\n verstuurt wordt en ik dus ook niets aan ReadLn heb, aangezien die op een \r\n wacht...
Als jij ook iets beter had gelezen dan zag je dat ik de timeout op 1 sec (of meer zet) om dit af te vangen 8)

  • martijn_brinkers
  • Registratie: November 2001
  • Laatst online: 31-10-2025
Als je naar de ReadLine code kijkt staat er:
function ReadLn(ATerminator: string = LF;
const ATimeout: Integer = IdTimeoutDefault; AMaxLineLength: Integer = -1): string; virtual;

Dus je kan zelf de terminator opgeven. Jij geeft daar dus '' op.... vreemd dus.... maak er dus LF van en je bent van je probleem af... (hoop ik :)

Bij de weg Borland heeft een eigen news server waar veel cracks rondhangen (waaronder ook degene die Indy hebben geschreven). Daar kan je meestal het best terecht met vragen
News Server: newsgroups.borland.com

  • Osiris
  • Registratie: Januari 2000
  • Niet online
TijnFLiP schreef op 12 januari 2003 @ 21:53:
Als je naar de ReadLine code kijkt staat er:
function ReadLn(ATerminator: string = LF;
const ATimeout: Integer = IdTimeoutDefault; AMaxLineLength: Integer = -1): string; virtual;

Dus je kan zelf de terminator opgeven. Jij geeft daar dus '' op.... vreemd dus.... maak er dus LF van en je bent van je probleem af... (hoop ik :)

Bij de weg Borland heeft een eigen news server waar veel cracks rondhangen (waaronder ook degene die Indy hebben geschreven). Daar kan je meestal het best terecht met vragen
News Server: newsgroups.borland.com
Ik heb het nog niet geprobeerd, maar een LF is een #10 volgend de Help en een #10 is toch een \n cq. 0x0A (Hex)??? Die wordt ook niet verstuurt door MSN AFAIK... Kzal nog eens ff-tjes de sniffer erbij pakken :)

  • martijn_brinkers
  • Registratie: November 2001
  • Laatst online: 31-10-2025
Ik neem aan dat MSN wel iets gebruikt om aan te geven dat het commando beeindigd is. Het kan natuurlijk ook zijn dat ze een 'hard coded' lengte hebben. Als dat zo is moet je dus geen ReadLn gebruiken maar Read ofzo

  • jelmervos
  • Registratie: Oktober 2000
  • Niet online

jelmervos

Simple user

Er wordt van te voren aangegeven hoelang een berecht is, beetje HTTP idee zeg maar:

Versturen:
code:
1
2
3
4
5
6
MSG 3 A 157
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
X-MMS-IM-Format: FN=Microsoft%20Sans%20Serif; EF=I; CO=000000; CS=0; PF=22

Hello! How are you?


Ontvangen:
code:
1
2
3
4
5
6
MSG example@passport.com Mike 157
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
X-MMS-IM-Format: FN=Microsoft%20Sans%20Serif; EF=I; CO=000000; CS=0; PF=22

Hello! How are you?


Er wordt dus als laatste parameter bij MSG opgegeven hoeveel bytes de inhoud is van het bericht.

[ Voor 39% gewijzigd door jelmervos op 12-01-2003 23:34 ]

"The shell stopped unexpectedly and Explorer.exe was restarted."


  • jelmervos
  • Registratie: Oktober 2000
  • Niet online

jelmervos

Simple user

Misschien heb je er iets aan, maar ik heb ooit deze classes gemaakt om een thread de TCPClient uit te laten lezen en een event af laten vuren als er data beschikbaar is. Hij leest dus niks uit voor jou:

Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
unit TCPClient;

interface

uses
  Classes, IdGlobal, IdTCPClient;

type
  TTCPClientReader = class;

  TTCPClient = class(TIdTCPClient)
  private
    FTCPClientReader: TTCPClientReader;
    FOnDataAvailable: TNotifyEvent;
    procedure DoDataAvailableEvent;
  public
    procedure Connect(const ATimeout: Integer = IdTimeoutDefault); override;
    procedure Disconnect; override;
  published
    property OnDataAvailable: TNotifyEvent read FOnDataAvailable write FOnDataAvailable;
  end;

  TTCPClientReader = class(TThread)
  protected
    FTCPClient: TTCPClient;
    InpLastSize: Integer;
  public
    constructor Create(TCPClient: TTCPClient);
    procedure Execute; override;
  end;

implementation

{ TTCPClient }

procedure TTCPClient.Connect(const ATimeout: Integer);
begin
  inherited Connect(ATimeout);
  if Connected then
    FTCPClientReader := TTCPClientReader.Create(Self);
end;

procedure TTCPClient.Disconnect;
begin
  if Assigned(FTCPClientReader) then FTCPClientReader.Terminate;
  inherited Disconnect;
end;

procedure TTCPClient.DoDataAvailableEvent;
begin
  if Assigned(FOnDataAvailable) then FOnDataAvailable(Self);
end;

{ TTCPClientReader }

constructor TTCPClientReader.Create(TCPClient: TTCPClient);
begin
  inherited Create(False);
  InpLastSize := 0;
  FTCPClient := TCPClient;
  FreeOnTerminate := True;
end;

procedure TTCPClientReader.Execute;
var
  InpSize: Integer;
begin
  while (not Terminated) and (FTCPClient.Connected) do
  begin
    try
      InpSize := FTCPClient.InputBuffer.Size;
      if (InpSize = 0) or (InpSize = InpLastSize) then
        InpLastSize := InpSize + FTCPClient.ReadFromStack(False, -1, False);
      FTCPClient.CheckForDisconnect(False, True);
      if FTCPClient.Connected then
        Synchronize(FTCPClient.DoDataAvailableEvent);
    except
      if FTCPClient.Connected then FTCPClient.Disconnect;
      Terminate;
    end;
  end;
end;

end.

"The shell stopped unexpectedly and Explorer.exe was restarted."

Pagina: 1