Autor Beitrag
*Eldorado
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 28

win7, 64 Bit;

BeitragVerfasst: Sa 23.04.11 13:27 
hi,
ich hab mir ein tutorial zu TServerSockel und TClientSockel duchgelesen und dementsprechend einen Client und einen Server geschrieben. Jetzt habe ich das problem, das die gesendeten Informationen via Socket.ReceiveText und Socket.SendText(), sowie Socket.SendBuf() nicht ankommen bzw nicht verarbeitet werden.
Wo habe ich den Fehler?

Hier sind die relevanten auszüge aus den Sourcen:
Server:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
procedure TfAnwendung.ServerClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var User:CustomRec;
begin
if Server.Socket.ReceiveText = 'On' then begin
Server.Socket.ReceiveBuf(User,SizeOf(User));
if CheckPW(User) = true
then EditOnline(true,User);
end;
if Server.Socket.ReceiveText = 'off' then begin
Server.Socket.ReceiveBuf(User,SizeOf(User));
if CheckPW(User) = true then
EditOnline(false,User);
end;

end;

procedure TfAnwendung.ServerClientConnect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
ShowMessage('Verbunden');
end;

Die Procedure ServerClientConnect funktioniert einwandfrei, Syntaxfehler bekomme ich auch nicht.

Client:
ausblenden volle Höhe Delphi-Quelltext
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:
procedure TfAnwendung.bAusClick (Sender: TObject);
begin
//Log Out noch implementieren
Client.Open;
Client.Socket.SendText('off');
Client.Socket.SendBuf(User,Sizeof(User));
Client.Close;
bEin.Visible:=true;
bNew.Visible:=true;
lePW.Visible:=true;
leUser.Visible:=true;
bAus.Visible:=false;
Image1.Visible:=false;
end;

procedure TfAnwendung.bEinClick (Sender: TObject);
begin
User.User:=leUser.Text;
User.PW:=lePW.Text;
User.IP:=PowerSock1.LocalIP;
//Log in noch imlpementieren
Client.Open;
Client.Socket.SendText('On');
Client.Socket.SendBuf(User,Sizeof(User));
Client.Close;
end;

procedure TfAnwendung.FormCreate(Sender: TObject);
begin
Client.Port:=10066;
Client.Host:='127.0.0.1';
end;


Btw: User ist ein Rec.
& Die Meldung der Verbindungen erscheinen.

Moderiert von user profile iconMartok: Code- durch Delphi-Tags ersetzt


Zuletzt bearbeitet von *Eldorado am Sa 23.04.11 14:09, insgesamt 1-mal bearbeitet
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19340
Erhaltene Danke: 1752

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Sa 23.04.11 13:52 
Kommt denn die Meldung, dass eine Verbindung da ist?

// EDIT:
Und wie immer noch der Link zum Tutorial: ;-)
www.delphi-library.de/topic_60744.html
*Eldorado Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 28

win7, 64 Bit;

BeitragVerfasst: Sa 23.04.11 14:08 
Ja die Meldung kommt. (gleich schnell oben editieren^^)
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19340
Erhaltene Danke: 1752

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Sa 23.04.11 14:25 
Hast du einmal einen Haltepunkt in ServerClientRead gesetzt? Kommt das Programm dort an? Und wenn ja, was passiert dann?

// EDIT:
Wenn ich mich recht entsinne, darf ReceiveText nicht mehrfach aufgerufen werden, oder?
*Eldorado Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 28

win7, 64 Bit;

BeitragVerfasst: Sa 23.04.11 14:40 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Hast du einmal einen Haltepunkt in ServerClientRead gesetzt? Kommt das Programm dort an? Und wenn ja, was passiert dann?

Ja habe ich, es fängt nichts an.

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:

Wenn ich mich recht entsinne, darf ReceiveText nicht mehrfach aufgerufen werden, oder?

Keine ahnung, ich kenn mich damit net aus.
Boldar
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 1555
Erhaltene Danke: 70

Win7 Enterprise 64bit, Win XP SP2
Turbo Delphi
BeitragVerfasst: Sa 23.04.11 18:09 
user profile icon*Eldorado hat folgendes geschrieben Zum zitierten Posting springen:

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:

Wenn ich mich recht entsinne, darf ReceiveText nicht mehrfach aufgerufen werden, oder?

Keine ahnung, ich kenn mich damit net aus.

Das war ein Wink mit dem Zaunpfahl an dich, das zu testen oder rauszufinden.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19340
Erhaltene Danke: 1752

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Sa 23.04.11 18:23 
user profile icon*Eldorado hat folgendes geschrieben Zum zitierten Posting springen:
Ja habe ich, es fängt nichts an.
Dann überprüfe einmal, ob die Firewall blockiert oder ähnliches. Denn wenn das Ereignis nicht einmal ausgelöst wird...

Warum schließt du eigentlich die Verbindung zum Server sofort wieder? Willst du nicht mehr machen als einmalig das zu schicken? :shock:

user profile icon*Eldorado hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:

Wenn ich mich recht entsinne, darf ReceiveText nicht mehrfach aufgerufen werden, oder?

Keine ahnung, ich kenn mich damit net aus.
Ich habe kurz nachgeschaut. :roll:
Wie ich dachte, das ist eine Methode, die direkt den Text abruft. Rufst du es erneut auf, wird der nächste Text angefragt...

Du musst also den Text z.B. in einer lokalen Stringvariable zwischenspeichern.

Davon abgesehen:
user profile icon*Eldorado hat folgendes geschrieben Zum zitierten Posting springen:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
procedure TfAnwendung.ServerClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var User:CustomRec;
begin
if Server.Socket.ReceiveText = 'On' then begin
Äußerst logisch... Du bekommst einen Socket übergeben, ignorierst den aber und nutzt irgendeinen anderen...
Das kann nicht klappen, was, wenn mehrere Verbindungen ankommen?

Also:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
procedure TfAnwendung.ServerClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
  ReceivedText: string;
begin
  ReceivedText := Socket.ReceiveText;
  if ReceivedText = 'On' then
  begin

  end
  else
  ...
Mr_Emre_D
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 114
Erhaltene Danke: 14



BeitragVerfasst: So 24.04.11 00:27 
1. Warum Verbindungen öffnen und anschließend direkt wieder schließen? Ich sehe nicht viel Sinn dahinter.

Du scheinst etwas fundamental falsch verstanden zu haben, was mir das hier zeigt:

ausblenden Delphi-Quelltext
1:
2:
if Server.Socket.ReceiveText = 'On' then begin
Server.Socket.ReceiveBuf(User,SizeOf(User));


2. Du musst dir das Senden und Empfangen von Daten so vorstellen:
Nimm dir ein Glas und stell es unter einen Wasserhahn und öffne den Wasserhahn. Nun fließt konstant Wasser hinein.
Wenn du das Glas nicht wegnimmst (entleerst->ReceiveText), wirds immer voller.

Nun kannste dir den Wasserhahn als "Sender" und das Glas als "Empfänger" vorstellen. Das Wasser ist der Datenfluss ("Stream") der unter Umständen ständig geschickt bzw. empfangen wird (solange halt Wasser durchfließt - dh. solange Daten vorhanden sind, bzw. geschickt werden).

Wenn du jetzt einmal ReceiveText aufrufst, aber dein Sender schon 'On' UND User geschickt hat, wird dir ReceiveText den ganzen String, dh. 'On<User>' zurückliefern.
Da hilft dann die Abfrage = 'On' nicht mehr, da kein 'On' allein ankommt! Dein Glas ist voll und wird immer voller!

Daher musst du dir überlegen, wie du Datensätze als Pakete interpretieren kannst. Diese kommen zwar als Pakete an, werden aber dann in den Puffer angehangen (gequeued) und der Puffer wächst und wächst, was zu Folge hat, dass du nicht mehr erkennen kannst, wo etwas beginnt und wo es endet.

Am einfachsten ist soetwas, wenn man einfach einen Seperator verwendet wie z.B. '#'.
Dann musst du das Angekommene eben parsen und schauen, ob du einen Datensatz aus dem Stream mit '#' am Ende rausfischen kannst um anschließend darauf zu reagieren.

Ein Beispiel, wie das dann aussähe:

User = 'Eldorado'.
du schickst 'On#'
du schickst User + '#' (='Eldorado#')
-
du empfängst 'On#Eldorado#';
du kopierst wiederholterweise alles bis zu # und entfernst alle Zeichen bis diesem inklusive -->
1. 'On'
2. 'Eldorado'


Zuletzt bearbeitet von Mr_Emre_D am So 24.04.11 08:23, insgesamt 2-mal bearbeitet
Boldar
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 1555
Erhaltene Danke: 70

Win7 Enterprise 64bit, Win XP SP2
Turbo Delphi
BeitragVerfasst: So 24.04.11 08:22 
Ich verweise auch mal auf die Umfangreichen Tutorials hier in der Library, besonders auf das Terminatorzeichen-Tutorial von Narses.
*Eldorado Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 28

win7, 64 Bit;

BeitragVerfasst: So 24.04.11 09:54 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
user profile icon*Eldorado hat folgendes geschrieben Zum zitierten Posting springen:
Ja habe ich, es fängt nichts an.
Dann überprüfe einmal, ob die Firewall blockiert oder ähnliches. Denn wenn das Ereignis nicht einmal ausgelöst wird...

Die Firewall hab ich ausgeschaltet gehabt.

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:

Warum schließt du eigentlich die Verbindung zum Server sofort wieder? Willst du nicht mehr machen als einmalig das zu schicken? :shock:

user profile iconMr_Emre_D hat folgendes geschrieben Zum zitierten Posting springen:
1. Warum Verbindungen öffnen und anschließend direkt wieder schließen? Ich sehe nicht viel Sinn dahinter.

naja, es ist ja noch nicht fertig und zur zeit wird halt mehr noch nicht übertragen.

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
user profile icon*Eldorado hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:

Wenn ich mich recht entsinne, darf ReceiveText nicht mehrfach aufgerufen werden, oder?

Keine ahnung, ich kenn mich damit net aus.
Ich habe kurz nachgeschaut. :roll:
Wie ich dachte, das ist eine Methode, die direkt den Text abruft. Rufst du es erneut auf, wird der nächste Text angefragt...

Du musst also den Text z.B. in einer lokalen Stringvariable zwischenspeichern.

okay, ich versuchs gleich mal anzupassen.

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:

Davon abgesehen:
user profile icon*Eldorado hat folgendes geschrieben Zum zitierten Posting springen:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
procedure TfAnwendung.ServerClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var User:CustomRec;
begin
if Server.Socket.ReceiveText = 'On' then begin
Äußerst logisch... Du bekommst einen Socket übergeben, ignorierst den aber und nutzt irgendeinen anderen...
Das kann nicht klappen, was, wenn mehrere Verbindungen ankommen?

naja das müsste sich mit der zwischenvariable ja auch mit erledigen oder?

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:

Also:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
procedure TfAnwendung.ServerClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
  ReceivedText: string;
begin
  ReceivedText := Socket.ReceiveText;
  if ReceivedText = 'On' then
  begin

  end
  else
  ...


user profile iconMr_Emre_D hat folgendes geschrieben Zum zitierten Posting springen:

Am einfachsten ist soetwas, wenn man einfach einen Seperator verwendet wie z.B. '#'.
Dann musst du das Angekommene eben parsen und schauen, ob du einen Datensatz aus dem Stream mit '#' am Ende rausfischen kannst um anschließend darauf zu reagieren.

Ein Beispiel, wie das dann aussähe:

User = 'Eldorado'.
du schickst 'On#'
du schickst User + '#' (='Eldorado#')
-
du empfängst 'On#Eldorado#';
du kopierst wiederholterweise alles bis zu # und entfernst alle Zeichen bis diesem inklusive -->
1. 'On'
2. 'Eldorado'

Sieht interesannt aus, mal schaun ob ichs umsetzten kann.

Auf an die arbeit und umbasteln.

---Moderiert von user profile iconNarses: Beiträge zusammengefasst---

So, ich hab jetzt mal ein wenig umgebastelt und mich entschlossen erstmal auf das SendBuf zu verzichten, da ich die syntax da sowieso nicht wirklich verstanden habe.
Jetzt läuft alles über SendText.
Desweiteren hab ich einfach mal die ganze komunikation in einem Memo mitschreiben lassen, wobei mir aufgefallen ist, das der Login text garnicht übertragen wird, aber der logoff, wobei beide eigentlich fast gleich aufgebaut sind.

Client:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
procedure TfAnwendung.bAusClick (Sender: TObject);
begin
Client.Open;
Client.Socket.SendText('off#'+User.User+'#'+User.PW+'#'+User.IP+'#');
Client.Close;
end;

procedure TfAnwendung.bEinClick (Sender: TObject);
begin
User.User:=leUser.Text;
User.PW:=lePW.Text;
User.IP:=PowerSock1.LocalIP;
Client.Open;
Client.Socket.SendText('stupid!');
Client.Socket.SendText('On#'+User.User+'#'+User.PW+'#'+User.IP+'#');
Client.Close;
end;

procedure TfAnwendung.FormCreate(Sender: TObject);
begin
Client.Port:=10066;
Client.Host:='127.0.0.1';
end;

Server:
ausblenden volle Höhe Delphi-Quelltext
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:
procedure TfAnwendung.FormCreate(Sender: TObject);
begin
Server.Port:=10066;
Server.Open;
end;

procedure TfAnwendung.ServerClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var User:CustomRec;
    MSG:string;
    tick:integer;
    todo:boolean;
begin
User.User:='';
User.PW:='';
User.IP:='';
MSG := Socket.ReceiveText;
Memo1.Lines.Add(MSG);
while (MSG[tick] <> '#'do begin
 if (MSG[tick] = 'o'and (MSG[tick+1] = 'n'and (MSG[tick+2] = '#')
  then todo:=true;
 if (MSG[tick] = 'o'and (MSG[tick+1] = 'f'and (MSG[tick+2] = 'f'and (MSG[tick+3] = '#')
  then todo:=false;
 inc(tick);
end;
inc(tick,3);
if todo = false
 then inc(tick);

while MSG[tick] <> '#' do begin
 User.User:=User.User+MSG[tick];
 inc(tick);
end;
inc(tick);

while MSG[tick] <> '#' do begin
User.PW:=User.PW+MSG[tick];
inc(tick);
end;
inc(tick);

while MSG[tick] <> '#' do begin
User.IP:=User.IP+MSG[tick];
inc(tick);
end;

if CheckPW(User) = true
then EditOnline(todo,User);
end;

procedure TfAnwendung.ServerClientConnect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
ShowMessage('Verbunden');
end;

end.

Nachwievor funktioniert ClientConnect.
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10184
Erhaltene Danke: 1256

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: So 24.04.11 23:49 
Moin!

user profile icon*Eldorado hat folgendes geschrieben Zum zitierten Posting springen:
ich hab mir ein tutorial zu TServerSockel und TClientSockel duchgelesen und dementsprechend einen Client und einen Server geschrieben.
Wenn ich mir den Code so ansehe, dann solltest du das Tutorial besser schnell wieder weglegen... :?

(min.) Zwei entscheidende Probleme:
  • Du (oder dieses "Tutorial") gehst davon aus, dass die Ereignisse bei einem asynchronen Socket was mit den gesendeten Daten zu tun haben. Das ist aber ein Trugschluss :arrow: FAQ-Beitrag dazu :les: :think:

  • Du hast doch jetzt schon mehrfach den Tipp bekommen, dass es keine sehr gute Idee ist, dauernd an der TCP-Verbindung rumzuschrauben. :nixweiss: Mach die Verbindung auf und halte sie solange offen, bis du sie nicht mehr brauchst. Da du ja auch scheinbar eine Authentifizierung machen willst, kannst du doch beim nächsten Connect gar nicht mehr mit Sicherheit sagen, ob es der gleiche Client ist! :gruebel:

  • Hier findest du einen ganz einfachen Einstieg in die Materie. :idea: ;)


user profile icon*Eldorado hat folgendes geschrieben Zum zitierten Posting springen:
Hier sind die relevanten auszüge aus den Sourcen:
Leg den Code bei Seite, das kann man nicht mehr retten. :| (alleine der Umgang mit dem Client-Socket ist eine Katastrophe - oder synchron beabsichtigt, aber jedenfalls nicht offensichtlich erkennbar, es fehlen dann ja auch die Exception-Handler)

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
FrEaKY
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 235


D7
BeitragVerfasst: Mo 25.04.11 19:59 
Das schreit nach einem Protokoll... zumindest ein simples.