Chat mit lnet

Alle Fragen zur Netzwerkkommunikation
Antworten
Thomebau
Beiträge: 6
Registriert: Fr 24. Sep 2010, 20:32

Chat mit lnet

Beitrag von Thomebau »

Hi,
Ich versuche grade einen Chat mit Elnet zu erstellen. Allerdings etwas umfangreicher als von mintpc hier beschrieben:http://www.lazarusforum.de/viewtopic.php?f=26&t=4397.

Wenn ich mein Programm im Servermodus starte und einen Client verbinde, läuft das so weit so gut. Trenne ich aber nun diesen Client (ordentlich über TCP), kackt der Server ab und meldet:
"Invalid buffersize 0 in Send."

Wenn ich eine Nachricht schicke erscheint diese am Server (wird dort auch ausgegeben) und am Client (die Nachricht wird am Client erst ausgegeben wenn der Server sie zurück sendet).
Das funktioniert also wie es soll! Egal ob mit festen String oder Verweis auf die Stringvariable.


Im Grunde genommen hängt es nur an einem Problem:
Und zwar akzeptiert Send Message leider keinen Verweis auf einen String, ein String selbst wird akzeptiert, dieses Problem taucht nur auf wenn sich ein Client abmeldet!

funktioniert nicht:

Code: Alles auswählen

//Server empfängt Nachricht
procedure TForm1.LTCPServerReceive(aSocket: TLSocket);
var EinNachricht:string;
begin
   begin
   aSocket.GetMessage(EinNachricht);
   MemoChatWindow.Lines.Add(EinNachricht);
   LTCPServer.IterReset;
      while (LTCPServer.IterNext=true)do
            LTCPServer.SendMessage(EinNachricht,LTCPServer.Iterator);
   end;
end;

das hier funktioniert:

Code: Alles auswählen

//Server empfängt Nachricht
procedure TForm1.LTCPServerReceive(aSocket: TLSocket);
var EinNachricht:string;
begin
   begin
   aSocket.GetMessage(EinNachricht);
   MemoChatWindow.Lines.Add(EinNachricht);
   LTCPServer.IterReset;
      while (LTCPServer.IterNext=true)do
            LTCPServer.SendMessage('EinNachricht',LTCPServer.Iterator);
   end;
end;
gibt dann zwar dann "EinNachricht" aus, aber zum testen ist das ja wurscht, String ist String.


und zwar hängt es hier:

Code: Alles auswählen

LTCPServer.SendMessage(EinNachricht,LTCPServer.Iterator);
vs:

Code: Alles auswählen

LTCPServer.SendMessage('EinNachricht',LTCPServer.Iterator);
Seltsamerweise ist dieser Fehler von dem Receive Ereignis des Server abhängig, nicht vom Disconnect obwohl der Fehler immer beim Trennen eines Clients zustande kommt :shock:


Ich weis echt nicht mehr weiter, ist essentieller Teil meines Chat Programmes, welches die vom Server empfangenen Nachrichten an alle Clients weiterleitet. Das kann ich nicht weg lassen.

Das is echt das einzige an dem es noch hängt, ansonsten ist das Ding fix und fertig, war ein Arsch voll Arbeit :cry:

Hier nochmal der ganze Quellcode wenns interessiert:
eeeee.txt
Quellcode
(6.03 KiB) 98-mal heruntergeladen

Displaced
Beiträge: 83
Registriert: So 12. Jul 2009, 10:08

Re: Chat mit lnet

Beitrag von Displaced »

Ich hatte ein ähnliches Problem.
Ich hab das dann allerdings wieder ganz anders gelöst. Und zwar hab ich lNet neu gezogen und es hatte geklappt.
Die andere Methode die ich dir empfehlen würde, wäre die gendanken zu machen über nen vernünftiges Protokoll.
Ich selbst arbeite sehr viel mit lnet und habe ebenfalls bereits ein Binärprotokoll geschrieben wodurch die Daten die gesendet werden niemals leer sein können.
Dadurch würdest du den Fehler von vorne rein ausschließen.

Thomebau
Beiträge: 6
Registriert: Fr 24. Sep 2010, 20:32

Re: Chat mit lnet

Beitrag von Thomebau »

Das lnet nicht so ganz das wahre ist dachte ich mir irgendwie schon, da sind ein paar hässliche Sachen drin. Aber ich fürchte da komme ich nicht drumrum, wir nutzen das in der Schule und ich wollte mal ein bisschen vorarbeiten^^ Blöd dass es nicht geht.

Wie hast du das denn gemacht dass keine leeren Nachrichten raus gehen?

EDIT: Ich hab das ganze jetzt mal umgangen dass er wenigstens nicht mehr abstürzt und man das Programm benutzen kann.

Code: Alles auswählen

//Server empfängt Nachricht
procedure TForm1.LTCPServerReceive(aSocket: TLSocket);
var EinNachricht:string;
begin
   begin
   aSocket.GetMessage(EinNachricht);
   MemoChatWindow.Lines.Add(EinNachricht);
   if EinNachricht='' then EinNachricht:=' ';
   LTCPServer.IterReset;
      while (LTCPServer.IterNext=true)do
            LTCPServer.SendMessage(EinNachricht,LTCPServer.Iterator);
   end;
end;
So ist die Nachricht nie leer, sie wird auch nicht gesendet, aber so gibt wenigstens nur der Server einen Error aus und stürzt nicht sofort ab.

schnullerbacke
Beiträge: 1187
Registriert: Mi 13. Dez 2006, 10:58
OS, Lazarus, FPC: Winux (L 1.2.xy FPC 2.6.z)
CPU-Target: AMD A4-6400 APU
Wohnort: Hamburg

Re: Chat mit lnet

Beitrag von schnullerbacke »

Code: Alles auswählen

//Server empfängt Nachricht
procedure TForm1.LTCPServerReceive(aSocket: TLSocket);
var EinNachricht:string;
begin
   begin
   aSocket.GetMessage(EinNachricht);
   MemoChatWindow.Lines.Add(EinNachricht);
   if EinNachricht='' then EinNachricht:=' ';
   LTCPServer.IterReset;
      while (LTCPServer.IterNext=true)do
            LTCPServer.SendMessage(EinNachricht,LTCPServer.Iterator);
   end;
end;
So ist die Nachricht nie leer, sie wird auch nicht gesendet, aber so gibt wenigstens nur der Server einen Error aus und stürzt nicht sofort ab.
Doppelt gemoppelt würde ich sagen, das hier sollte es auch tun:

Code: Alles auswählen

//Server empfängt Nachricht
procedure TForm1.LTCPServerReceive(aSocket: TLSocket);
var EinNachricht:string;
begin
   aSocket.GetMessage(EinNachricht);
   if Length(EinNachricht) > 0 then begin
     MemoChatWindow.Lines.Add(EinNachricht);
     LTCPServer.IterReset;
        while (LTCPServer.IterNext=true) do LTCPServer.SendMessage(EinNachricht,LTCPServer.Iterator);
   end; // of if Length(EinNachricht) > 0 then begin
end;
oder auch:

Code: Alles auswählen

//Server empfängt Nachricht
procedure TForm1.LTCPServerReceive(aSocket: TLSocket);
var EinNachricht:string;
begin
   aSocket.GetMessage(EinNachricht);
   MemoChatWindow.Lines.Add(EinNachricht);
   LTCPServer.IterReset;
   while ((LTCPServer.IterNext=true) and (Length(EinNachricht) > 0))  do LTCPServer.SendMessage(EinNachricht,LTCPServer.Iterator);
end;
Geh mal davon aus, dass die erste Form die bessere ist. Da wird nur was gemacht wenn auch tatsächlich ein Inhalt existiert.
Humor ist der Knopf, der verhindert, daß uns der Kragen platzt.

(Ringelnatz)

Thomebau
Beiträge: 6
Registriert: Fr 24. Sep 2010, 20:32

Re: Chat mit lnet

Beitrag von Thomebau »

Schöne Idee, danke für den Tipp ;)

MAC
Beiträge: 770
Registriert: Sa 21. Feb 2009, 13:46
OS, Lazarus, FPC: Windows 7 (L 1.3 Built 43666 FPC 2.6.2)
CPU-Target: 32Bit

Re: Chat mit lnet

Beitrag von MAC »

auch wenn es erstmal nichts zur sache tut:

Code: Alles auswählen

while (LTCPServer.IterNext=true) do
kann man ersetzen durch

Code: Alles auswählen

while LTCPServer.IterNext do
Denn das eine wäre Doppelt Gemoppelt...

Code: Alles auswählen

Signatur := nil;

Displaced
Beiträge: 83
Registriert: So 12. Jul 2009, 10:08

Re: Chat mit lnet

Beitrag von Displaced »

Mal abgesehen vom Doppelgemoppel:

lNet ist ja, wie der Name schon sagt bloß eine "lightweight" Network-component.
Dass man da noch ne Menge drum herum bauen sollte, ist damit ja quasi beschlossen.

Der Unterschied ist, dass ich keine Strings im eigentlichen Sinne verwende sondern array of byte..
Ich hab mir ne Buffer klasse gebaut, die mir meine Informationen zusammschustert und dann werden sie gesendet.
Momentan haben die Pakete (weil ich sie zu nem Protokoll kompatibel machen musste) folgenden Aufbau:

Packetsize (4byte) + PacketIndex (4byte) + PacketContent

Damit sind meine Nachrichten NIE leer weil immer mind. PacketIndex drin ist und dazu eben die Länge. Was zwar im endeffekt bedeutet ich sende immer 8 bytes, aber das ist mir relativ egal. Zur Optimierung könnte man natürlich noch das ganze begrezen auf 2 bytes oder 4 und 2 bytes, aber das nur am Rande..

PacketContent sieht dann so aus, dass meine Buffer klasse eben alles reinschreibt wie ich das brauche
Bytes bleiben bytes
Ints werden in 2bytes gepackt
longs in 4bytes
Strings ist dann ein konstrukt aus länge (4bytes) + string (array of byte)
Bei Lazarus muss man dazu aufpassen, dass die normalen strings nen mix sind aus unicode und ascii... sprich a-z ist jeweils 1byte aber öäü wären dann jeweils schon 2 bytes... daher array of char oder array of byte..

Das ist das ganze Geheimnis.

schnullerbacke
Beiträge: 1187
Registriert: Mi 13. Dez 2006, 10:58
OS, Lazarus, FPC: Winux (L 1.2.xy FPC 2.6.z)
CPU-Target: AMD A4-6400 APU
Wohnort: Hamburg

Re: Chat mit lnet

Beitrag von schnullerbacke »

Ich geh mal davon aus, das man dann aber mit einer entsprechenden Funktion was ähnliches erreichen kann:

Code: Alles auswählen

function CheckMsgLen(var InBuf):boolean;
var
  result: boolean;
begin
  result:= false;
  // hier die Testerei und
  result:= Expression;
  Return result;
end;
Die Deklaration

Code: Alles auswählen

funcname(var InBuf)
erzeugt eine unspezifizierte Variable ohne Typ, die man behandeln kann wie man will. Das kann also ein Pointer sein oder ein Array oder was immer man da reinpackt.
Ganz gediegen ist natürlich ein Mimetype im ersten Byte, das kann man dann als Settyp verarbeiten:

Code: Alles auswählen

if InBuf[0] in MyType then case InBuf[0] of
end;
"Umtypen" von InBuf (

Code: Alles auswählen

TType(InBuf).fieldname
) geht natürlich auch.
Da kann man seiner Kreativität freien Lauf lassen. :wink:
Humor ist der Knopf, der verhindert, daß uns der Kragen platzt.

(Ringelnatz)

Antworten