Scott
In 8.04 Dialog Doevents has a problem, do a search.
John
Announcement
Collapse
No announcement yet.
TCP Server multi-threading (New topic)
Collapse
X
-
OK I did NOT have this in my Thread -
DO
DIALOG DOEVENTS
LOOP
So that solves that and it works, but it takes like 4 OR 5 seconds for the thread to fire up now, and for the image or html page to be displayed - hardly worth it in my opinion, especially if I get 50-100 concurrent connections (Not likely but hey...)
FAR FAR faster just having all of that in my message pump for my callback function
So forget the server thread - but I will take all the advice you've given on my Globals and get those into a TYPE.........
So......Globals aside - I'm working on that, I'm not sure this is going to work....
So I was under the assumption that DDT with MODELESS dialog boxes would also suspend like a Modal does...not so....
This is entirely too slow...
Code:'============================================<tcpThreadProc>=============================================================== Function CreateNewConnectionThread(ByVal tcpCount As Long) As Long Static hThread As Long Local lResult As Long Thread Create ConnectionThreadProc(ByVal tcpCount) To hThread WaitForSingleObject hThread,10000 Function = hThread 'grab thread handle to close prematurely and properly if need be. End Function '========================================================================================== Function ConnectionThreadProc(ByVal tcpCount As Long) As Long 'Creates a modeless dialog box in a new thread so to avoid locking up main app. Local tDlg As Long Local lResult As Long Dialog New 0, "",,, 1,1, To tDlg 'modeless Dialog Show Modeless tDlg Call ConnectProc To lResult Do While IsFalse lResult Dialog DoEvents Loop Function = lResult End Function '========================================================================================== CallBack Function ConnectProc() As Long
Last edited by Scott Turchin; 13 Oct 2008, 07:15 PM.
Leave a comment:
-
Originally posted by Michael Mattias View Post>
(You do have this in your program somewhere? If not, that explains why you never get to where you want to go).
MCM
If I weren't just one hell of a nice guy, I'd suggest that your statement "his first simple and understandable problem is so hard for you to understand," constitutes a personal insult, which is not permitted here. But I can be be quite understanding when it's apparent English is not your first language.
John
Leave a comment:
-
Scott
You posted while I was writing the last reply (am a slow typist, won't comment on my thinking speed with my age).
First step, just change your thread dialog to MODAL, PB will now provide the message pump and this statement
Dialog End CbHndl,%TRUE
You may have other issues with different options per user but this should be a good first step.
John
Leave a comment:
-
>This is the modeless dialog message pump..
Typo or stray comment?
Message loop =
Code:DO DIALOG DOEVENTS LOOP or WHILE GetMessage( IF ISFALSE IsDlgMessage ( TranslateMessage DispatchMessage
MCM
Leave a comment:
-
Michael
I'm not a DDT guy
As such I have to rely on the Power Basic Manual which says
A modeless dialog must always have a message pump running while the dialog is running. Without a message pump, a modeless dialog will not be able to receive messages to redraw itself, etc.
…. the function will end. The window will still exist,
Immediately after calling the thread create function Scott does a Thread Close so the handle will be invalidated, the thread will have ended etc. so though his statement
Determined my thread is closing before anything can happen
Your latest “next step” example fascinates me but leaves me a little confused
ONE window can handle ALL current "connect and send" sessions
John
Leave a comment:
-
Thanks John - so back to my original using globals such as the socket - it's still failing on the TCP NOTIFY.
Code:This is the modeless dialog message pump.. Select Case CbMsg Case %WM_INITDIALOG Dialog Show State CbHndl, %SW_HIDE 'hide the window from flashing up SetTimer CbHndl, %IDT_TIMER2, 10000, ByVal %NULL hTcp = %INVALID_SOCKET hTcp = FreeFile Tcp Accept g_ntcpSocket As hTcp 'Debug shows #9 here Tcp Notify #hTcp, Accept Connect Recv Close To CbHndl As %TCP_HTML ' Tcp Notify #hTcp, Recv Close To CbHndl As %TCP_HTML 'xxxxxxxxxxxxxxxxxx Never gets to this point: xxxxxxxxxxxxxxxxxxxxx Case %TCP_HTML Select Case Lo(Word, CbLParam) Case %FD_READ If hTcp <> %INVALID_SOCKET Then
Leave a comment:
-
I'm not a DDT guy but I now what will happen if you do the SDK equivalent (CreateDialog).... the function will end. The window will still exist, so you could put a message loop in your code following the return from this function.
With "tDlg" being LOCAL, there will be no way to talk to it on that return, but that is actually not necessary since in the "connectproc" you will have a handle via CBHNDL.
Leave a comment:
-
Michael
Your knowledge of GUI far exceeds mine but in the following code snippet of Scotts
Code:Function ConnectionThreadProc(ByVal tcpCount As Long) As Long Local tDlg As Long Local lResult As Long Dialog New 0, "",,, 1,1, %WS_POPUP Or %WS_DLGFRAME To tDlg 'modeless Dialog Show Modeless tDlg Call ConnectProc To lResult End Function
I know I must be missing something but it seems to me that all this will do is create a dialog then immediately destroy it and as that is all that is in his thread isn't that End Function a coded Thread Function End?
Is the Thread Object not destroyed at this point?
John
Leave a comment:
-
No, he did NOT say the "thread ends"; he said, "the thread closes, not sure why"
At which point I noted:
"Threads" do not "close."
Thread HANDLES may be closed; but they don't do it on their own.
Thread FUNCTIONs end because you code them to end.
Thread FUNCTIONs end.
Thread OBJECTS are destroyed.
Thread HANDLES may be closed.
Go read TCP on what it means when you create a new socket which happens on every ACCEPT
If I weren't just one hell of a nice guy, I'd suggest that your statement "his first simple and understandable problem is so hard for you to understand," constitutes a personal insult, which is not permitted here. But I can be be quite understanding when it's apparent English is not your first language.
MCM
Leave a comment:
-
Michael
Why do you persist, you said it yourself
Thread FUNCTIONs end because you code them to end.
Determined my thread is closing before anything can happen
Go read TCP on what it means when you create a new socket which happens on every ACCEPT.
Forgetting all other complexities I have trouble understanding why his first simple and understandable problem is so hard for you to understand, just read his code, HE CREATES A WINDOW THEN THE THREAD ENDS.
John
Leave a comment:
-
Ok, just go to the next step...
Code:FUNCTION PbMain() IF condition THREAD CREATE ConnectAndSendFIle FUNCTION ConnectAndSendFile LOCAL Params.. DIALOG NEW .... (Create window to receive TCP notifications) DIALOG SET USER 1 = Pointer to parameter block DIALOG SHOW somehow (modal is OK, since you won't block anything) END FUNCTION FUNCTION DialogProc_TCPNotifications .. LOCAL hThread AS LONG , PParam as Param TYPE PTR WM_INITIDIALOG DIALOG GET USER CBHNDL, 1 TO pParam THREAD CREATE TCPONLYFUNCTION (@Param)
It is actually not necessary to have a separate notification window for each separate thread: ONE window can handle ALL current "connect and send" sessions.... as long as you use nothing but stack-based variables. (There's that GLOBAL thing attempting to bite you in a tender place again).
I know I would do it with but one notification window:
Code:FUNCTION PBMAIN() HWndNotify = CreateWindowEx (notification window, not visible, or maybe visible depending on my mood and the current phase of the moon) DIALOG NEW (primary user interface) passing hWndNotify as a param
MCMLast edited by Michael Mattias; 12 Oct 2008, 12:17 PM.
Leave a comment:
-
Scott
If you are using 8.03 or newer the look at THREADED variables they are Global to the thread (Yes PB put them in because sometimes GLOBALS are the best way to do things).
Agian I repeat my prior post, it will never work while you use Modeless Dialogs as you are now using them(there are ways).
There will never be a white screen of death as the thread dialogs should be hidden and if you do have a visible Dialog to give some info then it is only the main original in which you place info from the thread even Michael should agree with that.
John
Leave a comment:
-
OK Michael I studied this and I am getting the drift, EXCELLENT way to eliminate a couple of global variables.
HOWEVER - The point of this new thread is to run in a modeless dialog box, in the event a TCP connection locks up (Ya know, the white screen of death) - it will do so in a thread and not the main program, thus the next connection gets af resh thread, new window etc..
For that reason I am having a hard time seeing how to pass the socket to a callback function for the modeless dialog box without using a global variable, but then that COULD be the problem.........
I'm still trying to incorporate your code ab ove though, this may be a while LOL, the pointer is giving PB 8.4 a bad time...
Leave a comment:
-
>the thread closes, not sure why
"Threads" do not "close."
Thread HANDLES may be closed; but they don't do it on their own.
Thread FUNCTIONs end because you code them to end.
Leave a comment:
-
Scott
Been away for a couple of days, but did say was not easy.
Have only had a very quick look at your first code. I dont believe PB allows you to have nested functions within PB functions, so your thread only contains the creation of a modeless dialog and then the function ends (as its not doing anything to keep it alive so your dialog is promptly destroyed and never gets notified of a recv and the thread ends. Think I said in a prior post that I couldn't see why you were using modeless dialogs.
If the dialog was Modal then the thread would stay alive until you did a DIALOG END in the callback after completing the TCP SEND. Of course all the threads are then using the same callback which has other complexities particularly speed and to which thread does the incoming data belong to.
Would be nice to have something like "Start of Thread" "End of Thread" statements so you could move a dialog and its callback to the same thread.
Can't see any help to the process by waiting for single objects, or MMF's.
Micheal
NO nothing to do with CGI. Properly done this is not simple and unfortunately mosts your posts are just confusing the problem.
John
Leave a comment:
-
No a CGI application resides ON a webserver whereas this *IS* a webserver, although I could build a CGI app inside of it (In essence it does have a built in web page, thus could be CGI)...
Common Gateway Interface, never understood that really, just a server app by definition..
Anyway so my thread is failing right here, I put a msgbox here and it never gets there....the thread closes, not sure why...
Ya I go with globals and then go back and clean them up and try to localize them, makes me think on how to do it...
Code:Case %TCP_HTML msgbox "DEBUG" - never happens. Select Case Lo(Word, CbLParam) Case %FD_READ
Leave a comment:
-
Internet is not my strong suit but isn't...
"just trying to send an html file, and then close the connection."
the very definition of a "CGI" application?
Leave a comment:
-
>No just trying to send an html file, and then close the connection
Code:TYPE TheParams szFile AS ASCIIZ * %MAX_PATH connectionInfo hEventReady AS LONG ThreadId AS LONG ... END TYPE [THREAD ] FUNCTION ConnectandSendFile ( BYVAL pParam AS TheParams PTR) AS LONG LOCAL P AS TheParams @Param.ThreadId = THREADID ' set this for return P = @pParam ' copy params SetEvent P.hHEventReady ' release calling thread ' --------------------------------- ' Connect, send file whatever here ' ---------------------------------- hTCP = FREEFILE DIALOG new to hDLG or whatever END FUNCTION MACRO m_CreateThreadReadyEvent = CreateEvent (BYVAL %NULL, BYVAL %TRUE, BYVAL %FALSE, BYVAL %NULL) ' params:1 lpsecuritydescriptor, NULL = default security ' 2 Manual Reset TRUE/FALSE ' 3 initial state FALSE=unsignalled ' 4 lpsz name, or %NULL for no name FUNCTION WinMain () LOCAL P AS TheParams IF FileToSend THEN p.szFile = the file name p.ConnectionInfo = whatever p.heventready = m_createThreadReadyEvent THREAD CREATE ConnectAndSendFile (BYVAL VARPTR(P)) TO hThread WaitForSingleObject P.hEventReady CloseHandle P.hEventReady ThreadId = P.ThreadId ' return the thread ID of the launched thread ' --------------------------------------------- ' at this point you have the threadid and hThread of launched thread ' save or not for other purposes END IF
Because you do EVERYTHING in your THREAD FUNCTION, there is no data conflict (* as long as you lose your passion for GLOBAL variables)
You can create a seperate notification dialog in each Function but there's no reason they can't all use the same Dialog procedure... again assuming you terminate your relationship with GLOBAL variables.
Base everything in your DialogProc on stack-based variables (eg CBHNDL) and you'll be just fine.
MCM
Leave a comment:
-
No just trying to send an html file, and then close the connection.
Right now I get success on the TCP Accept etc to TCP_ECHO but it never gets to the TCP_ECHO, which is now named TCP_HTML
Code:'============================================<DialogProc>=============================================================== CallBack Function DialogProc() As Long Static ti As NOTIFYICONDATA 'For system tray Static p As POINTAPI 'FOR pop up menu Static nServerIP As Long Static tcpCount As Long Static txtHandle As Long Local lResult As Long Local hResult As Long Local lLoop As Long Local sTmp As String Dim hThread(1 To %MAXTHREADS) As Dword Select Case CbMsg Case %WM_INITDIALOG 'Set timer to refresh the page EVERY 1 min SetTimer CbHndl, %IDT_TIMER1, 60000, ByVal %NULL Control Handle CbHndl,%IDLABEL1 To g_lblHandle Control Handle CbHndl,%IDTEXT1 To g_txtHandle Control Handle CbHndl, %IDSTATUSBAR To g_hStatus ' Initialization handler Graphic Attach CbHndl,%IDC_GC1,ReDraw Graphic Color %Red,%Yellow Graphic Clear Graphic ReDraw Call CylonEyeThread() 'Running in System Tray? If IsTrue g_RuninSysTray Then ' ** Add tray icon ti.cbSize = SizeOf(ti) ti.hWnd = CbHndl ti.uID = g_hInst ti.uFlags = %NIF_ICON Or %NIF_MESSAGE Or %NIF_TIP ti.uCallbackMessage = %WM_TRAYICON ti.hIcon = g_hIcon ti.szTip = g_szMine & " " & g_szVer Shell_NotifyIcon %NIM_ADD, ti DestroyIcon ti.hIcon End If If IsTrue g_StayOnTop Then 'Stay on top or not SetWindowPos CbHndl, %HWND_TOPMOST, 0, 0, 0, 0, %SWP_NOMOVE Or %SWP_NOSIZE Else SetWindowPos CbHndl, %HWND_NOTOPMOST, 0, 0, 0, 0, %SWP_NOMOVE Or %SWP_NOSIZE End If If IsFalse Len(g_ServerIP) Then 'Was not user specified, grab from socket nServerIP = CCSServerIP(g_Port) Else 'otherwise user specified the IP - if it fails they know it is their fault nServerIP = inet_addr(ByVal VarPtr(g_ServerIP)) End If 'Write to log file: UpdateLogfile "#Software: " & g_szMine & " " & g_szVer,%FALSE,%TRUE UpdateLogFile "#Date: " & TimeStamp(),%FALSE,%TRUE UpdateLogFile "#Fields: date time s-ip cs-method s-port c-ip cs(User-Agent) cs(Referer) sc-bytes cs-bytes",%FALSE,%TRUE g_ntcpSocket = FreeFile Tcp Open Server Addr nServerIP Port g_Port As g_ntcpSocket TimeOut g_TimeOut If Err Then sTmp = "Couldn't create socket!" Control Set Text CbHndl,%IDLABEL1, sTmp Else 'What's the next TCP Count Tcp Notify g_ntcpSocket, Accept To g_hDlg As %TCP_ACCEPT sTmp = "Listening on " & g_ServerIP & ":" & Format$(g_Port) Control Set Text CbHndl,%IDLABEL1, sTmp End If Function = %TRUE Case %TCP_ACCEPT Select Case Lo(Word, CbLParam) Case %FD_ACCEPT 'Create the new thread here Incr tcpCount hThread(tcpCount) = CreateNewConnectionThread(tcpCount) Control Set Text CbHndl,%IDCONNLABELTL, Format$(tcpCount,"") Control Set Focus CbHndl, %IDLABEL1 Function = %TRUE End Select Case %WM_TIMER Select Case CbWParam Case %IDT_TIMER1 g_BBSDown = LoadHtmlPage() g_BBSDownImage = LoadImageFile() sTmp = g_szMine & " " & g_szVer & " - " & g_szCopyrite SendMessage g_hStatus, %WM_SETTEXT, 0, StrPtr(sTmp) For lLoop = 1 To tcpCount Thread Status hThread(lLoop) To lResult Select Case lResult Case %THREADALIVE Iterate Case %FALSE 'Function failed Thread Close hThread(lLoop) To hResult If IsFalse hResult Then Thread Close hThread(lLoop) To hResult 'TRY Again End Select Next End Select Case %WM_SIZE Control Send CbHndl,%IDSTATUSBAR,CbMsg,CbWParam,CbLParam Case %WM_COMMAND Select Case LoWrd(CbWParam) Case %IDM_EXIT If IsTrue g_UseSSL Then sTmp = "Stopping sTunnel.." SendMessage g_hStatus, %WM_SETTEXT, 0, StrPtr(sTmp) sTmp = "stunnel" sTmp = CCSStopService(ByVal CCSGetComputerName(), ByVal sTmp) End If g_Finished = %TRUE 'End Cylon eye AND tcp thread Dialog End CbHndl,%TRUE Case %IDM_HELP sTmp = AppPath & "Help\Index.html" ShellExecute ByVal %NULL, "open", ByVal StrPtr(sTmp), ByVal %NULL, ByVal %NULL, %SW_SHOWNORMAL Function = %TRUE Case %IDM_LOGFILE sTmp = g_LogFile ShellExecute ByVal %NULL, "open", ByVal StrPtr(sTmp), ByVal %NULL, ByVal %NULL, %SW_SHOWNORMAL Function = %TRUE Case %IDM_ABOUT Call ccsShellAbout(CbHndl, _ %FALSE, _ g_szMine,_ g_szVer,_ g_szCCS,_ g_szCopyrite,_ "Computer Creations Software;http://www.tngbbs.com/ccs",_ "",_ g_hIcon) Function = %TRUE Case %IDM_OPTIONS Call Options() 'This has to go here, locks up the & accelerators if done in OPTIONSDialogProc If IsTrue g_StayOnTop Then 'Stay on top or not SetWindowPos g_hDlg, %HWND_TOPMOST, 0, 0, 0, 0, %SWP_NOMOVE Or %SWP_NOSIZE Else SetWindowPos g_hDlg, %HWND_NOTOPMOST, 0, 0, 0, 0, %SWP_NOMOVE Or %SWP_NOSIZE End If Case %IDM_RESTORE If IsWindowVisible(CbHndl) = %FALSE Then Menu Attach g_hMenu, CbHndl ShowWindow CbHndl, %SW_SHOW Or %SW_SHOWNORMAL SetFocus CbHndl End If End Select Case %WM_TRAYICON Select Case LoWrd(CbLParam) ' ** Left button press Case %WM_LBUTTONDOWN, %WM_LBUTTONDBLCLK If IsWindowVisible(CbHndl) = %FALSE Then Menu Attach g_hMenu, CbHndl ShowWindow CbHndl, %SW_SHOW Or %SW_SHOWNORMAL SetFocus CbHndl End If ' ** Right button press Case %WM_RBUTTONDOWN If IsWindowVisible(CbHndl) = %FALSE Then SetForegroundWindow CbHndl GetCursorPos p TrackPopupMenu g_pMenu, 0, p.x, p.y, 0, CbHndl, ByVal %NULL Postmessage CbHndl, %WM_NULL, 0, 0 End If Function = 1 End Select Case %WM_DESTROY Tcp Close g_ntcpSocket KillTimer CbHndl, %IDT_TIMER1 Shell_NotifyIcon %NIM_DELETE, ti DestroyIcon ti.hIcon Case %WM_SYSCOMMAND Select Case CbWParam Case %SC_CLOSE Dialog End CbHndl,%TRUE Function = 1 Case %SC_MAXIMIZE Menu Attach g_hMenu, CbHndl Case %SC_MINIMIZE If IsFalse g_RunInSysTray Then Exit Function ShowWindow CbHndl, %SW_HIDE Menu Attach g_pMenu, CbHndl Function = %TRUE Exit Function End Select 'cbwparam for syscommand End Select End Function '============================================<tcpThreadProc>=============================================================== Function CreateNewConnectionThread(ByVal tcpCount As Long) As Long Static hThread As Long Local lResult As Long Thread Create ConnectionThreadProc(ByVal tcpCount) To hThread 'Unique number now Thread Close hThread To lResult Function = hThread 'grab thread handle to close prematurely and properly if need be. End Function '========================================================================================== Function ConnectionThreadProc(ByVal tcpCount As Long) As Long Local tDlg As Long Local lResult As Long Dialog New 0, "",,, 1,1, To tDlg 'modeless Dialog Show Modeless tDlg Call ConnectProc To lResult Function = lResult End Function '========================================================================================== CallBack Function ConnectProc() As Long Local sBuffer As String Local sPacket As String Local Header As String Local lResult As Long Static hTcp As Dword Static lHost As String Local ErrType As Long Select Case CbMsg Case %WM_INITDIALOG ' Dialog Show State cbhndl, %SW_HIDE 'hide the window from flashing up SetTimer CbHndl, %IDT_TIMER2, 10000, ByVal %NULL ' hTcp = %INVALID_SOCKET hTcp = FreeFile Tcp Accept g_ntcpSocket As hTcp 'Debug shows #9 here Tcp Notify hTcp, Recv Close To CbHndl As %TCP_HTML ErrType = GetLastError() If ErrType <> %ERROR_SUCCESS Then Call AppendTextToWindow(ByVal sPacket) End If Function = %TRUE Case %WM_TIMER 'IF They don't get connected in 5 seconds disconnect Select Case CbWParam Case %IDT_TIMER2 Tcp Close hTcp hTcp = %INVALID_SOCKET Dialog End CbHndl, %TRUE End Select Case %TCP_HTML Select Case Lo(Word, CbLParam) Case %FD_READ If hTcp <> %INVALID_SOCKET Then 'Grab client IP and insert here lHost = RemoteIp(ByVal hTcp) AppendTextToWindow TimeStamp() & " Connection established from: " & lHost ' Perform a receive-loop until there is no data left (ie, the end of stream) sBuffer = "" sPacket = "" Do Tcp Recv hTcp, 1024, sBuffer sPacket = sPacket & sBuffer If Len(sPacket) > 4096 Then Exit Do 'Buffer overflow prevention Loop Until sBuffer = "" Or IsTrue Eof(hTcp) Or IsTrue Err sPacket = Left$(sPacket,Len(sPacket)-2) & String$(50,"-") lResult = ParseAndUpdateLogfile(ByVal sPacket,ByVal hTcp) 'Updates window ' <-------------Send data and disconnect-------------> If IsFalse lResult Then 'html Header = "HTTP/1.1 200" & $CrLf Header = Header & "Server: " & g_szMine & $CrLf Header = Header & "Date: " & GetPCTimeandDate() & $CrLf Header = Header & "Content-Type: text/html" & $CrLf Header = Header & "Content-Length: " & Format$(Len(g_BBSDown)) & $CrLf Header = Header & "Cache-Control: no-cache" & $CrLf Tcp Send hTcp, Header & $CrLf Tcp Send hTcp, g_BBSDown Else 'jpg Header = Header & "HTTP/1.1 200" & $CrLf ' Header = Header & "Last-Modified: " & GetFileDateandTime(g_BBSDownImageFile) & " GMT" & $CrLf Header = Header & "Server: " & g_szMine & $CrLf Header = Header & "Date: " & GetPCTimeandDate() & $CrLf Header = Header & "Content-Type: image/jpeg" & $CrLf Header = Header & "Content-Length: " & Format$(Len(g_BBSDownImage)) & $CrLf Header = Header & "Accept-range: bytes" & $CrLf 'or something like that. Header = Header & "Cache-Control: no-cache" & $CrLf Header = Header & "Connection: close" & $CrLf Tcp Send hTcp, Header & $CrLf Tcp Send hTcp, g_BBSDownImage End If Tcp Close hTcp hTcp = %INVALID_SOCKET Dialog End CbHndl,%TRUE ' <-------------Send data and disconnect-------------> 'End connection here Else ErrType = GetLastError() If ErrType <> %ERROR_SUCCESS Then Call AppendTextToWindow(ByVal sPacket) End If End If Case %FD_CLOSE Tcp Close hTcp hTcp = %INVALID_SOCKET End Select End Select End Function
Last edited by Scott Turchin; 11 Oct 2008, 05:03 PM.
Leave a comment:
Leave a comment: