AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Netzwerke Anfängerfrage: Non Blocking TCP Client in einem Thread
Thema durchsuchen
Ansicht
Themen-Optionen

Anfängerfrage: Non Blocking TCP Client in einem Thread

Ein Thema von alzaimar · begonnen am 4. Dez 2009 · letzter Beitrag vom 7. Dez 2009
 
Astat

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

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

  Alt 4. Dez 2009, 17:17
Hallo alzaimar.

Du verwendest einen Asynchronen Socket, die Kommunikation wird mit dem Socket durch den Parameter (ctNonBlocking) auf WindowsMessages festgelegt.

WSAAsyncSelect(Socket, Wnd, Msg, AsyncStyle); Das heisst, es werden die Socket Events in die Application Message Queue (MSQ), zur Abarbeitung, durch den Mainthread gestellt.
Die Verwendung der TClientSocket Komponente mit dem Parameter (ctNonBlocking) in einem eigenen Thread macht keinen Sinn,
da der Motor, der den Socket am Leben hällt, die MSQ des Mainthreads ist.
Wenn du nicht die Mainthread Message Oueue verwenden willst, musst Du die Komponente umschreiben.
Ersetze das AllocateHwnd der Komponente durch folgenden Code.

Delphi-Quellcode:

function TCustomWinSocket.GetHandle: HWnd;
begin
  if FHandle = 0 then
    FHandle := AllocateHwnd(WndProc);
  Result := FHandle;
end;
Delphi-Quellcode:
function TCustomWinSocket.GetHandle: HWnd;
begin

  while _hWndMain = 0 do;

  if FHandle = 0 then
    FHandle := _hWndMain; //_hWndMain; //AllocateHwnd(WndProc);

  Result := FHandle;
end;
Delphi-Quellcode:
function MainWndProc(wnd: HWND; Msg: Integer; wp: WPARAM;
  lp: LPARAM): Integer; stdcall; forward;

var
  _Terminated : Boolean = false;
  _hWndMain : HWND = 0;
  _hThread : THandle = 0;
  _dwThreadID : dword = 0;

  TASyncMainWindowClass : TWndClass = (style: 0; lpfnWndProc: @MainWndProc;
    cbClsExtra: 0; cbWndExtra: 0; hInstance: 0; hIcon: 0; hCursor: 0;
    hbrBackground: 0; lpszMenuName: nil; lpszClassName: 'TAsyncServerMainWindowClass'
    );

function MainWndProc(wnd: HWND; Msg: Integer; wp: WPARAM; lp: LPARAM): Integer; stdcall;
var
  tMsg: TMessage;
begin
  Result := 0;
  if Msg = WM_CLOSE then DestroyWindow(wnd) else
  if _CustomWinSocket <> nil then begin
    tMsg.Msg := Msg;
    tMsg.WParam := wp;
    tMsg.LParam := lp;
    tMsg.WParamLo := LOWORD(wp);
    tMsg.WParamHi := HIWORD(wp);
    tMsg.LParamLo := LOWORD(lp);;
    tMsg.LParamHi := HIWORD(lp);;
    if not _CustomWinSocket.WndProc(tMsg) then
      Result := DefWindowProc(wnd, Msg, wp, lp)
  end else
    Result := DefWindowProc(wnd, Msg, wp, lp);
end;

procedure InitAplication;
begin
  TASyncMainWindowClass.hInstance := hInstance;

  TASyncMainWindowClass.lpszClassName := PChar(CreateClassID);

  if Windows.RegisterClass(TASyncMainWindowClass) = 0 then
    raiselastwin32error;

  _hWndMain := CreateWindowEx(WS_EX_TOOLWINDOW   , TASyncMainWindowClass.lpszClassName,
    '', WS_POPUP   , 0, 0, 0, 0, 0, 0, hInstance, nil);

  if _hWndMain = 0 then raiselastwin32error;
end;

procedure CleanupAplication;
begin
  WSACleanup;
  CloseHandle(_hThread);
  if _hWndMain <> 0 then begin
    DestroyWindow(_hWndMain);
    _hWndMain := 0;
  end;
end;

function RunAplication(p: pointer): integer;
var
  MsgRec : TMsg;
begin
  result := 0;

  SetThreadPriority(_hThread, THREAD_PRIORITY_TIME_CRITICAL);

  WSAStartup($0101, WSAData);

  InitAplication;

  while GetMessage(MsgRec, _hWndMain, 0, 0) do begin
    DispatchMessage(MsgRec)
  end;

  CleanupAplication;
  _Terminated := TRUE;
end;

....

initialization
  _hThread := beginthread(nil, 0, RunAplication, nil, 0, _dwThreadID);
end.
Also, kurz zusammengefasst:

Am einfachsten ist es, wenn du den Socket und die durch die Socket Messages getriggerten Callbacks,
im Mainthread (MainUnit) erstellst. Du verwaltest deine zusätzlich notwendigen Workerthreads von
diesem Punkt aus. Von hier aus (MainUnit) kannst du deine Threads Resumen, Starten Stoppen, und oder
mit Synchgronisationsobjekten (Events, Mutexe, Semaphoren, Critical Sections usw.) arbeiten.

Mach die SendSocket methode Threadsave, dann kann jeder Workerthread zu jeder Zeit gefahlos senden.
Erstelle deine Workerthreads, implementiere wenn notwendig Datenübergabe Prozeduren usw.

Tip:
Um eine gute Skalierung zu erreichen, den Socket alleine im Mainthread werkeln lassen.
Zusätzliche Codeteile in eigene Threads auslagern.


lg. Astat

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


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 16:16 Uhr.
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz