Einzelnen Beitrag anzeigen

Astat

Registriert seit: 2. Dez 2009
Ort: München
320 Beiträge
 
Lazarus
 
#6

Re: Anfängerfrage: Non Blocking TCP Client in einem Thread

  Alt 5. Dez 2009, 03:44
alzaimar hat geschrieben
  • So in etwa hatte ich das befürchtet, jedoch insgeheim gehofft, das die MSQ des Threads verwendet wird,
    den Socket erstellt oder man dem Sockets wenigstens sagen kann, das sie die MSQ des Threads verwenden sollen.

Nein, die Komponente verwendet die Main-MessageLoop und nicht die des Threads.
Dh. DispatchMessage wird im Mainthread aufgerufen, und die Messages, an die mit AllocateHwnd angegebene WndProc, des "Fensters" gesendet. Siehe vorherigen Post.

Delphi-Quellcode:

while GetMessage(MsgRec, _hWndMain, 0, 0) do begin
  DispatchMessage(MsgRec)
end;
Um in jedem Thread den du erzeugst, eine Messageloop zu implementieren, musst du folgendes ändern.

Die Globalen Variablen, und WndProc in die TClientSocket-Class integrieren.
Zu jedem neu erzeugten Client Objekt, MakeObjectInstance für die WndProc stdcall methode implementieren, und
einen eigenen Thread, der die Messageloop integriert (DispatchMessage) generieren.

alzaimar hat geschrieben
  • Eigentlich habe ich eine Multi-client-Anwendung, d.h. viele Clients sollen sich mit jeweils einem Server
    verbinden und mit dem Quatschen.

Also, wenn es unbedingt multiple Asynchrone Clients sein müssen, die in mehreren Threads unter einem Prozess laufen müssen,
und sich zu ein und demselben Server verbinden, musst Du die Komponeten-Klasse (ScktComp.pas) wie oben, und in den vorhergehenden Thread beschrieben umcodieren.

Normalerweise kann man mit einem Asynchronen Client Socket, wie in der ScktComp.pas Unit implementiert ist,
ganz ordentliche Client Server Anwendungen erstellen. Jedoch haben die Borländer einige Bugs in der ScktComp.pas
reingebaut, desshalb ist das Teil auch nicht Hochlast fähig.

Folgendes musst du ändern.

Delphi-Quellcode:

procedure TCustomWinSocket.Error(const Socket: TCustomWinSocket; const ErrorEvent: TErrorEvent;
  var ErrorCode: Integer);
begin
   Disconnect(FSocket); //-- Astat
   if Assigned(FOnErrorEvent) then FOnErrorEvent(Self, Socket, ErrorEvent, ErrorCode);
end;

function TCustomWinSocket.SendBuf(var Buf; const Count: Integer; var ErrorCode: integer): Integer;
begin
  Result := SOCKET_ERROR; // =0; korrigiert //-- Astat
  ErrorCode := ERROR_SUCCESS; //-- Astat
  if not FConnected then Exit;
  Result := send(FSocket, Buf, Count, 0);
  if Result = SOCKET_ERROR then
  begin
    ErrorCode := WSAGetLastError;
    if (ErrorCode <> WSAEWOULDBLOCK) then
    begin
      Error(Self,eeSend,ErrorCode);
      Disconnect(FSocket);
      if ErrorCode <> 0 then
        raise ESocketError.CreateFmt(sWindowsSocketError,
          [SysErrorMessage(ErrorCode), ErrorCode, 'send']);
    end;
  end;
end;
Was ich derzeit noch nicht verstehe, warum du aus einem Prozess viele Asynchrone Clientverbindungen
zu ein und demselben Server benötigst?

Kann mir eigentlich kein Szenario vorstellen, wo das notwendig ist?

Normalerweise reicht eine Asynchrone Connection um den Server mit allem zu versorgen was dieser benötigt.
Ist ja deshalb ein Asynchroner Socket, in dem ich wie wild Daten schreiben kann, ohne auf ein Handshake wie bei
einer Synchronen Übertragung achten zu müssen.
Sollte es um einen Lasttest gehen, verwende einfach Blockierend Sockets, die du dann ohne Probleme
in multiplen Threads aufrufen kannst.

ClientSocket := Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) alzaimar hat geschrieben
  • Du meinst, ich soll einfach die TClientSockets im Hauptprogramm instantiieren und den Threads als Parameter übergeben?
    Die Threads biegen dann die Events (OnConnected, OnRead usw. auf ihre eigenen Handler um und das klappt?O)

Nein, die Threads biegen da die Events nicht hin, die Events werden im Mainthread (Mainunit) getriggert.
Ich vertrete hier den Ansatz, dass nur eine Einzige asynchrone Verbindung zum Server besteht.
Wie geschrieben, verstehe ich noch nicht die Notwendigkeit multipler Asynchroner Clientverbindungen,
da man ja alles über eine einzige Asynchrone Verbindung abhandeln kann.
Ich vermute hier mal folgendes Szenario:

Der Server ist als "Blockierend" -->> Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) implementiert, also wie ein Webserver.
Connectet sich nun ein asynchroner Client, muss dieser das Handshake (Blockierent) nachbauen, ist natürlich möglich,
aber total overdozed. Hier verwendet man "blockierende Sockets" -->> Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP),
dabei sendet man die Daten, und ruft anschließend Recv auf, dies reagiert erst wenn die Gegenstelle antwortet
(Server sendet Response zurück), fertig.

Also ich vermute mal, dass bei deinem Problem Blockierende Sockets die Lösung sein könnten?!


Würde mich interessieren, ob dem so ist?!

Wenn du Asynchrone und oder Synchrone Socket brauchst, sag einfach bescheid, hab da fix und fertige
DLL's (Synchron, Asynchron) Client und Server incl. Source, Hochlast Getestet.
Asynchrone Client Server Anwendung mit ~10000 Client Verbindungen.
Synchrone Client Server Anwendung mit 2 X Quad Xeon mit ca. 3000 Requests/s bei ~ 25Kb Daten in einem 1 GB Netz.

Hoffe etwas geholfen zu haben.

lg. Astat
Lanthan Astat
06810110811210410503210511511603209711003210010110 9032084097103
03211611111604403209711003210010110903210010510103 2108101116122
11610103209010110510810103206711110010103210511003 2068101108112
10410503210310111509910411410510109810111003211910 5114100046
  Mit Zitat antworten Zitat