Page 1 of 1
Do tcp/ip sockets block my program ?
Posted: Fri Apr 18, 2025 8:13 am
by MarkDM
I just discovered Purebasic. I want to make a GUI, the data is coming from a C-program on Raspberry Pi via TCP.
My testprogram receives every second a character and should display it in a TexGadget.
Problem: then TextGadget and the Window are frozen as long as the Tcp-connection is open.
There is only one update: this is when the Networkserver is closed (after 10 messages).
What can be wrong ?
Code: Select all
EnableExplicit
Define Font1, Value, Event, Port, ServerEvent, ClientID, Quit
Define *Buffer
Define Buf$ {100}
OpenConsole()
Port = 6832
*Buffer = AllocateMemory(100)
If OpenWindow(0, 0, 0, 270, 160, "TextGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
TextGadget(1, 10, 70, 250, 40, "0", #PB_Text_Center)
Font1 = LoadFont(#PB_Any, "Arial Rounded MT" , 20, #PB_Font_Bold)
SetGadgetFont(1, FontID(Font1))
Else
PrintN("Error Can't create window")
Goto FinishProgram
EndIf
If CreateNetworkServer(0, Port, #PB_Network_IPv4 | #PB_Network_TCP, "192.168.0.11")
PrintN("PureBasic Server created ")
Repeat
ServerEvent = NetworkServerEvent()
If ServerEvent
ClientID = EventClient()
Select ServerEvent
Case #PB_NetworkEvent_Connect
PrintN("A new client has connected !")
Case #PB_NetworkEvent_Data
PrintN("Client has send a packet !")
ReceiveNetworkData(ClientID, *Buffer, 100)
Print("String: ")
Buf$ = PeekS(*Buffer, -1, #PB_Ascii)
Print(Buf$)
SetGadgetText(1, Left(Buf$,1))
Case #PB_NetworkEvent_Disconnect
MessageRequester("PureBasic - Server", "Client "+ClientID+" has closed the connection...", 0)
Quit = 1
EndSelect
EndIf
Until Quit = 1
PrintN("quit the server.")
CloseNetworkServer(0)
Else
PrintN("Error Can't create the server (port in use ?).")
EndIf
FinishProgram:
PrintN("Press return to exit")
Input()
CloseConsole()
End
Re: Do tcp/ip sockets block my program ?
Posted: Fri Apr 18, 2025 9:49 am
by SMaag
Try a delay first, to give the OS the chance to update the program's GUI
(For posting code use the '</>' code option!)
Re: Do tcp/ip sockets block my program ?
Posted: Fri Apr 18, 2025 1:05 pm
by mk-soft
Welcome !
It's not quite that simple. With a GUI, all GUI events must always be processed.
A server should be outsourced to a thread. To get started with PurerBasic but first another solution
to process the server events in the GUI event loop. To do this, the WaitWindowEvent is exited every 10ms to process the server events.
Here is something rough quickly put together for testing.
Update
Code: Select all
;-TOP
#ProgramTitle = "Main Window"
#ProgramVersion = "v1.01.2"
Enumeration Windows
#Main
EndEnumeration
Enumeration MenuBar
#MainMenu
EndEnumeration
Enumeration MenuItems
#MainMenuAbout
#MainMenuExit
EndEnumeration
Enumeration Gadgets
#MainList
EndEnumeration
Enumeration StatusBar
#MainStatusBar
EndEnumeration
Global Font1, Value, Event, Port, ServerEvent, ClientID, Quit, IsInit
Global *Buffer
Global Buf$
Procedure Logging(Text.s)
AddGadgetItem(#MainList, -1, Text)
SetGadgetState(#MainList, CountGadgetItems(#MainList) - 1)
SetGadgetState(#MainList, -1)
EndProcedure
Procedure InitServer()
Port = 6832
*Buffer = AllocateMemory(1024)
If CreateNetworkServer(0, Port, #PB_Network_IPv4 | #PB_Network_TCP)
Logging("PureBasic Server created ")
ProcedureReturn #True
Else
Logging("Error: PureBasic Server not created ")
ProcedureReturn #False
EndIf
EndProcedure
Procedure DoServerEvent()
Protected len
Repeat
Select NetworkServerEvent()
Case #PB_NetworkEvent_Connect
ClientID = EventClient()
Logging("A new client has connected !")
Case #PB_NetworkEvent_Data
ClientID = EventClient()
Logging("Client has send a packet !")
len = ReceiveNetworkData(ClientID, *Buffer, 1024)
Buf$ = PeekS(*Buffer, len, #PB_Ascii)
Logging("String: " + Buf$)
Case #PB_NetworkEvent_Disconnect
ClientID = EventClient()
Logging("Client "+ ClientID + " has closed the connection...")
Case #PB_NetworkEvent_None
Break
EndSelect
ForEver
EndProcedure
Procedure UpdateWindow()
Protected dx, dy
dx = WindowWidth(#Main)
dy = WindowHeight(#Main) - StatusBarHeight(#MainStatusBar) - MenuHeight()
; Resize gadgets
ResizeGadget(#MainList, 0, 0, dx, dy)
EndProcedure
Procedure Main()
Protected dx, dy
#MainStyle = #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MaximizeGadget | #PB_Window_MinimizeGadget
If OpenWindow(#Main, #PB_Ignore, #PB_Ignore, 800, 600, #ProgramTitle , #MainStyle)
; Menu
CreateMenu(#MainMenu, WindowID(#Main))
MenuTitle("&File")
CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
MenuItem(#PB_Menu_About, "")
CompilerElse
MenuItem(#MainMenuAbout, "About")
CompilerEndIf
; Menu File Items
CompilerIf Not #PB_Compiler_OS = #PB_OS_MacOS
MenuBar()
MenuItem(#MainMenuExit, "E&xit")
CompilerEndIf
; StatusBar
CreateStatusBar(#MainStatusBar, WindowID(#Main))
AddStatusBarField(#PB_Ignore)
; Gadgets
dx = WindowWidth(#Main)
dy = WindowHeight(#Main) - StatusBarHeight(#MainStatusBar) - MenuHeight()
ListViewGadget(#MainList, 0, 0, dx, dy)
; Bind Events
BindEvent(#PB_Event_SizeWindow, @UpdateWindow(), #Main)
IsInit = InitServer()
Repeat
Select WaitWindowEvent(10) ;- Release Wait min 10 ms
Case #PB_Event_CloseWindow
Select EventWindow()
Case #Main
Break
EndSelect
Case #PB_Event_Menu
Select EventMenu()
CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
Case #PB_Menu_About
PostEvent(#PB_Event_Menu, #Main, #MainMenuAbout)
Case #PB_Menu_Preferences
Case #PB_Menu_Quit
PostEvent(#PB_Event_CloseWindow, #Main, #Null)
CompilerEndIf
Case #MainMenuExit
PostEvent(#PB_Event_CloseWindow, #Main, #Null)
Case #MainMenuAbout
MessageRequester("About", #ProgramTitle + #LF$ + #ProgramVersion, #PB_MessageRequester_Info)
EndSelect
Case #PB_Event_Gadget
Select EventGadget()
Case #MainList
Select EventType()
Case #PB_EventType_Change
;
EndSelect
EndSelect
EndSelect
DoServerEvent()
ForEver
If IsInit
CloseNetworkServer(0)
FreeMemory(*buffer)
EndIf
EndIf
EndProcedure : Main()
Re: Do tcp/ip sockets block my program ?
Posted: Fri Apr 18, 2025 2:18 pm
by NicTheQuick
@mk-soft: Don't you think it is better to do it like this?
Code: Select all
Repeat
Select WaitWindowEvent(1) ;- Release Wait min 10 ms
Case #PB_Event_None
DoServerEvent()
...
ForEver
This way first all the window events can be completed first before doing any network stuff.
I think I would be even better to use `WindowEvent()` here and only add a Delay(0) if there were no Network and no Window events. For that `DoServerEvent()` has to be modified too and for example return the number of processed events. If there were no network events at all it returns 0 and then one could do the Delay(0) to manually give other processes processing time.
Why to do it like this? In your example it could always last 10 ms until an other stream of network events is getting processed. 10ms are a long time to wait for a modern PC. So I would reduce the Delay to 0 to just give the scheduler of the operating system a hint that it can schedule other processed now and that's it.
But of course you are right with using a thread for a network server. That would be the best solution!
Re: Do tcp/ip sockets block my program ?
Posted: Fri Apr 18, 2025 2:30 pm
by mk-soft
I also use 10 ms for my server threads if no server events have occurred. This is completely OK for 99.9% of the application.
However, the server events should then be processed with priority. The GUI then handles everything in the gap.
But it is worth considering.
The example is ok to try out,
But as a running application it is not the right way, because the GUI event loop is known to be interrupted by the operation of menus or resize and thus the server events as well.
So you will also have to deal with threads later.
Re: Do tcp/ip sockets block my program ?
Posted: Fri Apr 18, 2025 4:10 pm
by infratec
The way to go is to put the network stuff in an own thread and communicate with the GUI via PostEvent()
Re: Do tcp/ip sockets block my program ?
Posted: Fri Apr 18, 2025 4:22 pm
by MarkDM
Thanks for your help. I added 3 lines of coding after the SetGadgetText function:
Code: Select all
Repeat
Event = WaitWindowEvent(1)
Until Event = #PB_Event_None
Now it works good.
Re: Do tcp/ip sockets block my program ?
Posted: Fri Apr 18, 2025 4:26 pm
by NicTheQuick
MarkDM wrote: Fri Apr 18, 2025 4:22 pm
Thanks for your help. I added 3 lines of coding after the SetGadgetText function:
Code: Select all
Repeat
Event = WaitWindowEvent(1)
Until Event = #PB_Event_None
Now it works good.
It may look like it's working good. But that's still not enough. You always need to process window events, even when you not change any Gadgets. There are events firing when you move the mouse cursor or move the window or a lot of other stuff. You can not rely on waiting for network event to also process window events.
Re: Do tcp/ip sockets block my program ?
Posted: Fri Apr 18, 2025 4:57 pm
by MarkDM
I understand. But this target application is only displaying information. There is no user input.
Thanks for your advice.
BTW, is there a way to get rid of the pointervariable *buffer in
Code: Select all
ReceiveNetworkData(ClientID, *Buffer, 100)
I want to get the data immediately in the stringvariable Buf$, without PeekS.
Is that possible ? I learned there is no 'cast' available as in C-language.
Re: Do tcp/ip sockets block my program ?
Posted: Fri Apr 18, 2025 5:03 pm
by Quin
MarkDM wrote: Fri Apr 18, 2025 4:57 pm
BTW, is there a way to get rid of the pointervariable *buffer in
Code: Select all
ReceiveNetworkData(ClientID, *Buffer, 100)
I want to get the data immediately in the stringvariable Buf$, without PeekS.
Is that possible ? I learned there is no 'cast' available as in C-language.
No, unfortunately. PB has SendNetworkString, but no ReceiveNetworkString().
Re: Do tcp/ip sockets block my program ?
Posted: Fri Apr 18, 2025 6:35 pm
by mk-soft
@MarkDM
Please also take a close look at my example. You may only read as many characters from the buffer as the number of bytes returned from ReceiveNetworkData.