Multithreaded NetworkServer

Just starting out? Need help? Post your questions and find answers here.
wayne-c
Enthusiast
Enthusiast
Posts: 335
Joined: Tue Jun 08, 2004 10:29 am
Location: Zurich, Switzerland

Multithreaded NetworkServer

Post by wayne-c »

I am implementing a multithreaded NetworkServer at the moment, and have found out some strange behaviors while using the internal PB commands. Probably somebody can help me with the following considerations (only pseudo-code):

The main questions where I am, after my tests, totally unsure are:
  • - it turns out that ReceiveNetworkData is NOT thread safe?
    - SendNetworkData however IS thread safe?
    - or should none of them be used inside a thread?
This is NOT working because ReceiveNetworkData is inside Thread:

Code: Select all

Thread(ClientID)
	Data = ReceiveNetworkData(ClientID)
	Perform actions on Data
	SendNetworkData

CreateNetworkServer
	#PB_NetworkEvent_Data
		CreateThread(ClientID)
This SEEMS to be working (when putting ReceiveNetworkData outside of the thread),
even though SendNetworkData is still inside the thread:

Code: Select all

Thread(Data)
	Perform actions on Data
	SendNetworkData()

CreateNetworkServer
	#PB_NetworkEvent_Data
		Data = ReceiveNetworkData
		CreateThread(Data)
Or is it even better (or required?) to move SendNetworkData also outside of the thread?
Like that:

Code: Select all

Global NewList Responses()
Global Mutex

Thread(Data)
	Perform actions on Data
	LockMutex
	Add Response Responses()
	UnlockMutex

CreateNetworkServer
	Repeat
		#PB_NetworkEvent_Data
			Data = ReceiveNetworkData
			CreateThread(Data)
		
		LockMutex
		Foreach Responses()
			SendNetworkData(Responses())
		Next
		ClearList(Responses())
		UnlockMutex
	Forever
Any comments, best practices or experiences welcome!

Best regards
As you walk on by, Will you call my name? Or will you walk away?
User avatar
mk-soft
Always Here
Always Here
Posts: 5409
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Multithreaded NetworkServer

Post by mk-soft »

ThreadSafe must be activated in any case.
Then there are some queries that you have to protect with your own mutex. "EventClient()".

Run each server in its own thread. Get ReceiveData in the ServerThread and transfer the data into a new thread to send.

Fetching the data into a new thread makes no sense with the small data of maximum 65kB.
Assume that it also leads to problems if ReceiveNetworkData calls the NetworkEventServer again in the superior thread.

Code: Select all

; Dies ist der Server-Dienst der die Daten im Hintergrund verarbeitet

Global ServerMutex = CreateMutex()

Procedure ThreadServer(*ServerData.udtServerData)
  Protected Event, ConnectionID, keyConnectionID.s, count, Text.s, Name.s, ok, time, *Buffer, Size, TransactionID, ProtocolID
  Protected NewList ClosedConnectionID()
  Protected NewList ListConnectionID()
  
  With *ServerData
    
    CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
      Protected StopNap = BeginWork(#NSActivityLatencyCritical | #NSActivityUserInitiated, Hex(*ServerData))
    CompilerEndIf
    
    time = ElapsedMilliseconds()
    
    Repeat
      LockMutex(ServerMutex)
      Event = NetworkServerEvent(\ServerID)
      If Event
        ConnectionID = EventClient()
        keyConnectionID = Hex(ConnectionID)
      EndIf
      UnlockMutex(ServerMutex)
      Select Event
        Case #PB_NetworkEvent_Connect
          ; Daten für Client anlegen
          TcpNewClientData(ConnectionID, \ServerID)
          thLogging("Network: Client Connected: ID " + keyConnectionID)
...
Part of Modul_NetworkTCP: Link: https://www.purebasic.fr/german/viewtop ... =8&t=31321
Server and Client: https://www.purebasic.fr/german/viewtop ... 10#p351410
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
the.weavster
Addict
Addict
Posts: 1537
Joined: Thu Jul 03, 2003 6:53 pm
Location: England

Re: Multithreaded NetworkServer

Post by the.weavster »

Here's my suggestion:

Create a Map with Str(ConnectionID) as the key so any incoming network data is added to the relevant member in the map by the main thread.
Once you have a complete request from a client create a new thread to handle that request.
Once the request has been handled use PostEvent from the child thread to instruct the main thread to delete the map member.
Post Reply