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