Page 1 of 1
CreateNetworkServer(), Clarification on capabilities
Posted: Tue Aug 23, 2022 10:23 pm
by Oso
I'm experimenting with CreateNetworkServer() following two great examples at the bottom of this page...
https://www.purebasic.com/documentation ... ndex.html
I'm pleasantly surprised that the server will successfully service multiple client connections. I was expecting it to be available for only 1 simultaneous client at a time. I've done some work with Visual Basic winsock in the past and I was not able to achieve this with VB. A few questions I have...
1. How does PB achieve multiple clients in this way? I can see from the task manager that it doesn't spawn a new server process for each client (i.e. like Unix tty connections), unless there's something I haven't found. I'm guessing that it negotiates a new port with each new client. Anyway, it seems to work beautifully, but I'd love to have it confirmed that there are no gotchas that I haven't thought about
2. In the server example, the memory which is addressed by the pointer isn’t cleared, so if the client sends a packet containing ABCDEF, followed by a packet containing XYZ, there will be XYZDEF in memory. I tried adding #Null to the end of the string at the client side, but it just adds numeric zero. Is there a simple way to clear memory, or is there a better way?
Code: Select all
*Buffer = AllocateMemory(1000)
ReceiveNetworkData(ClientID, *Buffer, 1000)
3. The server process has a "repeat until quit = 1" loop, which causes the CPU to consume 99 – 100%. What would be the recommended solution to that?
Re: CreateNetworkServer(), Clarification on capabilities
Posted: Tue Aug 23, 2022 10:50 pm
by mk-soft
1) The network functions of PureBasic work very well.
However, a lot of editing still needs to be done. It is not the receive packet that is read out, but the receive buffer of the system. So you have to take care of the completeness of the data yourself. For example, if you send data of up to 65kb at a time via TCP/IP, it will not arrive in the receive buffer all at once. This is because the data in the network is split into different packets and must be reassembled in the programme. This is normal and therefore many protocols also use header information about the size of the data.
2) The PB network server works as listening and informs you via an event that a new client has connected. To manage the clients you should use MAP.
3) The server should not be processed in the main scope, but in a thread. Here you can also build a server event loop, where a delay of 10 ms takes the CPU load away.
4) Read at wiki how the protocol TCP/IP works. Also the meaning of the layers in the ISO model
Small base for server thread:
Code: Select all
Structure udtClientData
ConnectionID.i
Time.i
Date.i
Login.i
Name.s
Text.s
EndStructure
Structure udtServerData
*ThreadID
*ServerID
ExitServer.i
Map Client.udtClientData()
EndStructure
Global ExitApplication
Global ServerData.udtServerData
Procedure ThreadServer(*ServerData.udtServerData)
Protected Event, ConnectionID, keyConnectionID.s, count, Text.s, Name.s, ok, time
Protected len, *buffer
With *ServerData
time = ElapsedMilliseconds()
*buffer = AllocateMemory($FFFF)
Repeat
Event = NetworkServerEvent(\ServerID)
If Event
ConnectionID = EventClient()
keyConnectionID = Hex(ConnectionID)
EndIf
Select Event
Case #PB_NetworkEvent_Connect
If FindMapElement(\Client(), keyConnectionID)
;TODO
DeleteMapElement(\Client(), keyConnectionID)
EndIf
AddMapElement(\Client(), keyConnectionID)
\Client()\ConnectionID = ConnectionID
\Client()\Time = ElapsedMilliseconds()
\Client()\Date = Date()
;TODO
Case #PB_NetworkEvent_Data
len = ReceiveNetworkData(ConnectionID, *Buffer, $FFFF)
If FindMapElement(\Client(), keyConnectionID)
\Client()\Time = ElapsedMilliseconds()
;TODO
EndIf
Case #PB_NetworkEvent_Disconnect
If FindMapElement(\Client(), keyConnectionID)
;TODO
DeleteMapElement(\Client(), keyConnectionID)
EndIf
Case #PB_NetworkEvent_None
Delay(10)
EndSelect
Until \ExitServer
CloseNetworkServer(\ServerID)
\ThreadID = 0
\ServerID = 0
\ExitServer = 0
ClearMap(\Client())
FreeMemory(*buffer)
EndWith
EndProcedure
Re: CreateNetworkServer(), Clarification on capabilities
Posted: Tue Aug 23, 2022 11:37 pm
by Oso
mk-soft wrote: Tue Aug 23, 2022 10:50 pm
1) The network functions of PureBasic work very well.
However, a lot of editing still needs to be done. It is not the receive packet that is read out, but the receive buffer of the system. So you have to take care of the completeness of the data yourself. For example, if you send data of up to 65kb at a time via TCP/IP, it will not arrive in the receive buffer all at once. This is because the data in the network is split into different packets and must be reassembled in the programme. This is normal and therefore many protocols also use header information about the size of the data.
Thanks for this. From testing so far, it looks like PB always correctly identifies the particular client from the EventClient() result, so it's surprisingly close to what I need. I understand that if the client sends > 64kb, the packets might not arrive in sequence. Is that what your sample code is dealing with? A lot of it is new to me.
I'm still surprised that PB supports multiple client connections, without us needing to handle a separate process for each client. What if two clients send data at exactly the same time? Does it process them in turn?
mk-soft wrote: Tue Aug 23, 2022 10:50 pm
2) The PB network server works as listening and informs you via an event that a new client has connected. To manage the clients you should use MAP.
It was more a case of dealing with the string being shorter than the last string received. The memory contains XYZDEF, but in fact the DEF was a remnant from the string that the client (or different client) sent previously. I noticed just now that the number of characters is available, so that's solved.
Code: Select all
chrsreceived.i = ReceiveNetworkData()
... but yes, I'd like to better understand your reference to MAP

Re: CreateNetworkServer(), Clarification on capabilities
Posted: Wed Aug 24, 2022 1:39 am
by mk-soft
Sent data up to 65kb also arrives in the correct order, but not necessarily all data arrives at once. This is taken care of by the TCP/IP protocol. If several clients send, they are also separated correctly. You just have to assign the data to the right client until they are complete.
You can also use MAPS for this by using the ConnectionID as a string for the map key.
Re: CreateNetworkServer(), Clarification on capabilities
Posted: Wed Aug 24, 2022 7:38 pm
by Oso
mk-soft wrote: Wed Aug 24, 2022 1:39 am
Sent data up to 65kb also arrives in the correct order, but not necessarily all data arrives at once. This is taken care of by the TCP/IP protocol. If several clients send, they are also separated correctly. You just have to assign the data to the right client until they are complete.
Thanks, just trying to follow your example code. Are you staying inside that block of code until the client disconnects, or is there some other way that your know you have all the client's packets?
Re: CreateNetworkServer(), Clarification on capabilities
Posted: Wed Aug 24, 2022 11:05 pm
by mk-soft
Oso wrote: Wed Aug 24, 2022 7:38 pm
Thanks, just trying to follow your example code. Are you staying inside that block of code until the client disconnects, or is there some other way that your know you have all the client's packets?
This is the problem that many do not understand. The TCP/IP protocol takes care of many basic communications. Transmission of data, checksum and repetition, establishment and termination of the connection.
But not the length of all the data that is transmitted. Or where the data ends and where the next data begins. Here you have to become active yourself. For example, with control characters STX and ETX or with header info with lengths of the data, etc.