Another threaded server.
Posted: Sun Aug 26, 2012 4:00 am
Because sometimes we can't see the forest for the trees! Allow me to explain: I had requested from Fred a command that would 'increment' if you will the NetworkServerEvent(), so that in a loop, the next query of NetworkServerEvent() would return the next client connected. I asked for this because I wanted to create a thread that would receive the data in the socket input buffer, without the system indicating #PB_NetworkEvent_Data for an existing client connection. In a sense, a duplicate #PB_NetworkEvent_Data notification was occurring. Note that this is not what was really happening, and it's NOT a bug. It's just that it took longer for the thread to spawn and read the data from the client, then it took for my loop to come back around and interrogate NetworkServerEvent() again. I found in my testing that only in receiving data from the client connection is what increments the NetworkServerEvent().
I swear I do my best thinking in the bathroom, as it occurred to me there that I should instead create the thread to handle the new connection based upon the server event #PB_NetworkEvent_Connect instead of #PB_NetworkEvent_Data. I'm not sure how much of a difference it makes in the overall performance of a program, but I wanted to offload the work of receiving and sending network data entirely to the threads.
Here's what I ended up with, if it can help anyone out there, great! Please note that this code uses a Windows socket API to return the amount of data in the receive buffer.
I swear I do my best thinking in the bathroom, as it occurred to me there that I should instead create the thread to handle the new connection based upon the server event #PB_NetworkEvent_Connect instead of #PB_NetworkEvent_Data. I'm not sure how much of a difference it makes in the overall performance of a program, but I wanted to offload the work of receiving and sending network data entirely to the threads.
Here's what I ended up with, if it can help anyone out there, great! Please note that this code uses a Windows socket API to return the amount of data in the receive buffer.
Code: Select all
EnableExplicit
Procedure ProcessRequest(clientNumber)
Protected *memoryLocation
Protected length.i
Protected result.i
Protected amountRead.i
Protected attemptCount.i
Protected socketHandle.i
Protected memLength.i = 10000
Protected maxReadTrys.i = 20
Protected socketTimeout.i = 100
Protected errNumber.i = 0
PrintN("Client " + Str(clientNumber) + " connected")
socketHandle = ConnectionID(clientNumber)
*memoryLocation = AllocateMemory(10000)
Repeat
attemptCount = 0
amountRead = 0
; loop until we have received data, or our timeout has been exceeded
Repeat
result = ioctlsocket_(socketHandle, #FIONREAD, @length)
If result < 0; socket error
amountRead = result
errNumber = WSAGetLastError_()
Break
ElseIf result > 0; socket error
amountRead = result * -1
errNumber = WSAGetLastError_()
Break
ElseIf length > 0; we have data in the receive buffer
If length > memLength
length = memLength
EndIf
; loop here until we've read in all the data in the buffer
While length > 0
result = ReceiveNetworkData(clientNumber, *memoryLocation + amountRead, length)
If result > 0
amountRead = amountRead + result
length = length - result
Else
amountRead = result * -1
errNumber = WSAGetLastError_()
length = 0
EndIf
Wend
Break
Else
Delay(socketTimeout)
attemptCount = attemptCount + 1
If attemptCount > maxReadTrys; if still nothing received, just get out
Break
EndIf
EndIf
ForEver
; show what we ended up with
Select amountRead
Case 0
PrintN("Client " + Str(clientNumber) + " received nothing from socket")
Case 1 To 65535
PrintN("Client " + Str(clientNumber) + " received " + Str(amountRead) + " bytes: " + PeekS(*memoryLocation, result))
Default
PrintN("Client " + Str(clientNumber) + " received an error: " + Str(errNumber) + ", thread terminating")
EndSelect
If amountRead < 0
Break
EndIf
ForEver
FreeMemory(*memoryLocation)
EndProcedure
Define NSEvent.i
Define thisClient.i
Define keyPressed.s
Define serverNumber.i
Define portNumber.i = 8901
; initialize the network and create the server needed
InitNetwork()
serverNumber = CreateNetworkServer(#PB_Any, portNumber)
OpenConsole()
PrintN("Started Network Server on port " + Str(portNumber))
PrintN("Press Escape to exit")
PrintN("")
Repeat
NSEvent = NetworkServerEvent() ; if we receive data, it will be indicated here
Select NSEvent
Case #PB_NetworkEvent_Connect ; a socket has connected
thisClient = EventClient() ; get the event client identifier
CreateThread(@ProcessRequest(), thisClient); threaded procedure to process incoming data
Case #PB_NetworkEvent_Data ; raw data has been received
Case #PB_NetworkEvent_File ; uploading a file
Case #PB_NetworkEvent_Disconnect; a socket disconnected
Default; no server event occurred
EndSelect
Delay(20); sleep so we don't hammer the processor
keyPressed = Inkey()
Until keyPressed = #ESC$
PrintN("Escape pressed, press <enter> to terminate this process")
CloseNetworkServer(serverNumber)
Input()
End