AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Netzwerke Chat Server empfängt immer nur einmal
Thema durchsuchen
Ansicht
Themen-Optionen

Chat Server empfängt immer nur einmal

Ein Thema von Luckie · begonnen am 18. Mär 2005 · letzter Beitrag vom 19. Mär 2005
Antwort Antwort
Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#1

Chat Server empfängt immer nur einmal

  Alt 18. Mär 2005, 17:25
Ich bin gerade dabei einen kleinen Chat mit Server und Clients zu programmieren. Dabei benutze ich keine Komponenten. Der Server wartet dabei in einem Thread auf Clients, die sich verbinden. Jeder Client kommt in ein Array. Dann geht der Server im Thread jedes mal dieses Array durch und guckt, ob vom entsprechenden Client was kommt:
Delphi-Quellcode:
function ServerThread(p: Pointer): Integer;
var
  TempConSocket: TSocket;
  i: Integer;
  MsgBuffer: array[0..255] of Char;
resourcestring
  rsListen = 'Listening...';
  rsSocketOK = 'Neuer Client hat sich verbunden.';
  rsSocketError = 'Ungültige Socket';
  rsMsg = 'Client: %s';
begin
  bRunning := True;
  if listen(acceptSock, 10) <> SOCKET_ERROR then
  begin
    AddLogText(hApp, IDC_LV, rsListen, 2);
    while bRunning do
    begin
      listen(acceptSock, 10);
      TempConSocket := accept(acceptSock, nil, nil);
      if TempConSocket <> INVALID_SOCKET then
      begin
        SetLength(conSocket, length(conSocket)+1);
        conSocket[High(conSocket)] := TempConSocket;
        AddLogText(hApp, IDC_LV, rsSocketOK, 2);
      end
      else
        AddLogText(hApp, IDC_LV, rsSocketError, 0);
      for i := 0 to length(conSocket) - 1 do
      begin
        if recv(conSocket[i], MsgBuffer, sizeof(MsgBuffer), 0) > 0 then
          AddLogText(hApp, IDC_LV, Format(rsMsg, [String(MsgBuffer)]), 2);
        Zeromemory(@MsgBuffer, sizeof(MsgBuffer));
      end;
    end;
  end
  else
    AddLogText(hApp, IDC_LV, SysErrorMessage(WSAGetLastError), 0);
  result := 0;
end;
Aber irgendwie kann ich nur einmal was an den Server senden. Alles weitere kommt nicht an. irgendwo, muss da ein Denkfehler von mir sein.
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
Benutzerbild von Jens Schumann
Jens Schumann

Registriert seit: 27. Apr 2003
Ort: Bad Honnef
1.644 Beiträge
 
Delphi 2009 Professional
 
#2

Re: Chat Server empfängt immer nur einmal

  Alt 18. Mär 2005, 17:37
Hallo Luckie
Zitat von Luckie:
if recv(conSocket[i], MsgBuffer, sizeof(MsgBuffer), 0) > 0 then
AddLogText(hApp, IDC_LV, Format(rsMsg, [String(MsgBuffer)]), 2);...
Ich habe zwar noch nie mit den API's programmiert, aber es sieht so aus, als ob hier aus der Verbindung gelesen wird. Aber nur einmal. Kann es sein, dass das was Du sendest in mehrere Pakte aufgeteilt wird und nur das erste Paket aus der Verbindung liest? Evt. solltest solange aus der Verbindung lesen bis recv 0 zurückliefert.
I come from outer space to save the human race
  Mit Zitat antworten Zitat
Basilikum

Registriert seit: 9. Aug 2003
389 Beiträge
 
Delphi 7 Professional
 
#3

Re: Chat Server empfängt immer nur einmal

  Alt 18. Mär 2005, 19:42
du verwendest die Sockets im Blocking-Mode, sprich:

Thread startet, listen macht Port auf, accept blockiert, bis eine Connection eingeht, danach blockiert recv, bis das erste TCP-Segment eintrifft, danach wieder accept, welches aber blockiert, bis eine Connection eingeht, danach blo.... while true do ;

entweder lässt du einen Thread als Listener laufen, der dann pro akzeptierter Connection einen weiteren Thread spawned...
oder du betreibst die Sockets im Non-Blocking-Mode.... mehr dazu in der WinSock-Referenz (Stichworte: select / ioctlsocket)
  Mit Zitat antworten Zitat
Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#4

Re: Chat Server empfängt immer nur einmal

  Alt 18. Mär 2005, 22:55
Aaaah. Danke, das war meine Wissenslücke. Ich habe jetzt für jeden neuen Client einen eigenen Thread. Nur habe ich jetzt ein konzeptionelles Problem:
Delphi-Quellcode:
function ClientThread(p: Pointer): Integer;
var
  Sock: TSocket;
  MsgBuffer: array[0..255] of Char;
resourcestring
  rsMsg = 'Client: %s';
begin
  Sock := PClientThreadParams(p)^.Sock;
  while True do
  begin
    if recv(Sock, MsgBuffer, sizeof(MsgBuffer), 0) > 0 then
      AddLogText(hApp, IDC_LV, Format(rsMsg, [string(MsgBuffer)]), 2);
  end;
  FreeMem(p, sizeof(TClientThreadParams));
end;
Ich habe jetzt alle Nachrichten, die ankommen, "auf dem Server". Wie verteile ich sie jetzt am besten wieder auf die Clients?
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
Basilikum

Registriert seit: 9. Aug 2003
389 Beiträge
 
Delphi 7 Professional
 
#5

Re: Chat Server empfängt immer nur einmal

  Alt 19. Mär 2005, 00:01
vermutlich wirst du nicht um den Non-Blocking-Mode herumkommen.... und für die Kommunikation zwischen den Client-Threads wird irgend eine Art von Thread-Safen Queue benötigt...

pseudo-code:
Code:
while ClientConnected do begin

  if networkDataAvailable then pushQueueData

  if queueDataAvailable then sendNetworkData

end;
(wobei die *DataAvailable für beispielsweise 200ms blockieren, wenn keine Daten vorhanden sind, so dass nicht die gesamte CPU beübt wird.... die daraus resultierende Latenz ist bei einem Chat-System nicht störend...)

auf Dinge wie concurrent Socket-Operationen mehrere Threads auf dem selben Socket würde ich mich nicht einlassen... das kracht über kurz oder lang...

PS: hier spielst du mit dem Feuer (access violation / live lock):
Delphi-Quellcode:
while True do
  begin
    if recv(Sock, MsgBuffer, sizeof(MsgBuffer), 0) > 0 then
      AddLogText(hApp, IDC_LV, Format(rsMsg, [string(MsgBuffer)]), 2);
  end;
besser so:
Delphi-Quellcode:
while true do begin
  r:=recv(Sock, MsgBuffer, sizeof(MsgBuffer) - 1, 0); // #0 muss auch Platz haben
  if not (r > 0) then break; // recv gibt 0 zurück, wenn Connection geschlossen wurde

  MsgBuffer[r]:=#0;
  AddLogText(hApp, IDC_LV, Format(rsMsg, [string(MsgBuffer)]), 2);
end;
  Mit Zitat antworten Zitat
Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#6

Re: Chat Server empfängt immer nur einmal

  Alt 19. Mär 2005, 00:15
Zitat von Basilikum:
vermutlich wirst du nicht um den Non-Blocking-Mode herumkommen....
Ich hatte gerade, als ich du das über blocking und non-blocking geschrieben hast, etwas im Internet gestöbert. da wurde allgemein gesagt, dass man non-blocking sockets nicht verwenden sollte.

Zitat:
und für die Kommunikation zwischen den Client-Threads wird irgend eine Art von Thread-Safen Queue benötigt...
Ich habe mir das so überlegt: Die Nachricht wird in einen gloablen String geschrieben. Jedesmal, wenn was ankommt, feuert der ClientThread einen Event und der ServerThread, der die ClientThreads erstellt, schickt die Nachricht dann Reih um an alle Clients. Das heißt, ich bräuchte zusätzlich noch ein Array mit den SocketASdressen der Clients. Oder könnte man auch auf dem Port einen Broadcast schicken? Wenn ja, wie geht das?
`
Zitat:
auf Dinge wie concurrent Socket-Operationen mehrere Threads auf dem selben Socket würde ich mich nicht einlassen... das kracht über kurz oder lang...
Kannst du das etwas näher ausführen? das sind so meine ersten Schritte in der Netzwerkprogrammierung.

Zitat:
PS: hier spielst du mit dem Feuer (access violation / live lock):
Delphi-Quellcode:
while True do
  begin
    if recv(Sock, MsgBuffer, sizeof(MsgBuffer), 0) > 0 then
      AddLogText(hApp, IDC_LV, Format(rsMsg, [string(MsgBuffer)]), 2);
  end;
besser so:
Delphi-Quellcode:
while true do begin
  r:=recv(Sock, MsgBuffer, sizeof(MsgBuffer) - 1, 0); // #0 muss auch Platz haben
  if not (r > 0) then break; // recv gibt 0 zurück, wenn Connection geschlossen wurde

  MsgBuffer[r]:=#0;
  AddLogText(hApp, IDC_LV, Format(rsMsg, [string(MsgBuffer)]), 2);
end;
Ups. Danke.
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
Basilikum

Registriert seit: 9. Aug 2003
389 Beiträge
 
Delphi 7 Professional
 
#7

Re: Chat Server empfängt immer nur einmal

  Alt 19. Mär 2005, 08:13
Zitat von Luckie:
Zitat von Basilikum:
vermutlich wirst du nicht um den Non-Blocking-Mode herumkommen....
Ich hatte gerade, als ich du das über blocking und non-blocking geschrieben hast, etwas im Internet gestöbert. da wurde allgemein gesagt, dass man non-blocking sockets nicht verwenden sollte.
das würde mich etwas erstaunen, eine solche Pauschal-Aussage... vermutlich unter bestimmten Bedingungen, oder ?

Zitat von Luckie:
Zitat:
und für die Kommunikation zwischen den Client-Threads wird irgend eine Art von Thread-Safen Queue benötigt...
Ich habe mir das so überlegt: Die Nachricht wird in einen gloablen String geschrieben. Jedesmal, wenn was ankommt, feuert der ClientThread einen Event und der ServerThread, der die ClientThreads erstellt, schickt die Nachricht dann Reih um an alle Clients. Das heißt, ich bräuchte zusätzlich noch ein Array mit den SocketASdressen der Clients. Oder könnte man auch auf dem Port einen Broadcast schicken? Wenn ja, wie geht das?
das meinte ich mit den concurrent Socket-Operationen: einerseite würde ja der Client-Thread im recv warten, und der Server versucht gleichzeitig noch per send (auf dem selben Socket) Daten abzusetzen.
"Port Broadcasts" gibts nicht.

als Quit'n'Dirty Variante könntest du die Windows-Message-Queue missbrauchen (PostThreadMessage, etc). So must du nicht selber eine thread-safe queue implementieren.
und innerhalb der Client-Threads mit select() für einige 100ms auf Netzwerk-Daten warten, dann kurz die Window-Message-Queue prüfen, danach wieder auf Netzwerk-Daten warten. Du brauchst dann lediglich ein Array auf alle Thread-IDs, die allerdings wieder thread-safe sein muss....

Zitat von Luckie:
Zitat:
auf Dinge wie concurrent Socket-Operationen mehrere Threads auf dem selben Socket würde ich mich nicht einlassen... das kracht über kurz oder lang...
Kannst du das etwas näher ausführen? das sind so meine ersten Schritte in der Netzwerkprogrammierung.
siehe oben

ein grundlegend anderer Ansatz wäre, alle Sockets mit einem einzigen Thread zu bedienen:
- Socket auf non-blocking schalten
- mittels select() auf ein Ereignis (eingehende Verbindung oder Daten vorhanden) eines der vorhandenen Sockets (Server-/Client-Sockets) warten
- entsprechend reagieren (Connection akzepiteren, Daten lesen und weitersenden)

würde ich jedoch nicht verwenden:
- keine saubere Kapselung der Clients gegeneinander
- riesiger Thread-Code, unübersichtlich, fehleranfällig
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:53 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz