Do tcp/ip sockets block my program ?

Just starting out? Need help? Post your questions and find answers here.
MarkDM
New User
New User
Posts: 5
Joined: Fri Apr 18, 2025 7:45 am
Location: Flanders, Belgium

Do tcp/ip sockets block my program ?

Post 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  
 
SMaag
Enthusiast
Enthusiast
Posts: 325
Joined: Sat Jan 14, 2023 6:55 pm
Location: Bavaria/Germany

Re: Do tcp/ip sockets block my program ?

Post 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!)

Code: Select all

    Delay(10)	; 
    
  Until Quit = 1

User avatar
mk-soft
Always Here
Always Here
Posts: 6246
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Do tcp/ip sockets block my program ?

Post 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()
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
User avatar
NicTheQuick
Addict
Addict
Posts: 1519
Joined: Sun Jun 22, 2003 7:43 pm
Location: Germany, Saarbrücken
Contact:

Re: Do tcp/ip sockets block my program ?

Post 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!
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.
User avatar
mk-soft
Always Here
Always Here
Posts: 6246
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Do tcp/ip sockets block my program ?

Post 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.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
infratec
Always Here
Always Here
Posts: 7618
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Do tcp/ip sockets block my program ?

Post by infratec »

The way to go is to put the network stuff in an own thread and communicate with the GUI via PostEvent()
MarkDM
New User
New User
Posts: 5
Joined: Fri Apr 18, 2025 7:45 am
Location: Flanders, Belgium

Re: Do tcp/ip sockets block my program ?

Post 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.
User avatar
NicTheQuick
Addict
Addict
Posts: 1519
Joined: Sun Jun 22, 2003 7:43 pm
Location: Germany, Saarbrücken
Contact:

Re: Do tcp/ip sockets block my program ?

Post 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.
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.
MarkDM
New User
New User
Posts: 5
Joined: Fri Apr 18, 2025 7:45 am
Location: Flanders, Belgium

Re: Do tcp/ip sockets block my program ?

Post 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.
Quin
Addict
Addict
Posts: 1133
Joined: Thu Mar 31, 2022 7:03 pm
Location: Colorado, United States
Contact:

Re: Do tcp/ip sockets block my program ?

Post 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().
User avatar
mk-soft
Always Here
Always Here
Posts: 6246
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Do tcp/ip sockets block my program ?

Post 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.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
Post Reply