Page 1 of 1

Network Question

Posted: Mon May 09, 2011 5:59 pm
by Zefz
Neither the manual or the code samples are really clear on this. Let's say this is my server loop:

Code: Select all

    Repeat
      
      Protected Event.w = NetworkServerEvent()
      If Event
        
        ClientID.q = EventClient()
        
        Select Event
            
            ;Someone new has connected to us
          Case #PB_NetworkEvent_Connect
            SendNetworkMessage( "Client " + IPString(GetClientIP(ClientID)) + " is trying to connect..." )
              
            ;Ask for connection data
            PokeB(*NetworkBuffer, #Network_EstablishConnection)
            SendNetworkData(ClientID, *NetworkBuffer, 1)
            
            ;Someone is trying to send us some network data
          Case #PB_NetworkEvent_Data
            ReadNetworkData( ClientID )
            
            ;Someone is sending us a file!? We dont want that!
          Case #PB_NetworkEvent_File
            ;Ignore file sending! Simply drop the packet
            
            ;Someone has disconnected from us
          Case #PB_NetworkEvent_Disconnect
            PrintN("Client " + Str(ClientID) +" has closed the connection...")
            DisconnectClient(ClientID, "Client has disconnected.", #True)
            
        EndSelect
      EndIf
      
     Until Not Event
ReadNetworkData() is a procedure that simply parses raw data from the *NetworkBuffer (that you recieve through RecieveNetworkData). Each time data is sent, it is first stamped with a "header byte" indicating what type of packet this is.

Code: Select all

Procedure ReadNetworkData(ConnectionID)
  RecieveNetworkData( ConnectionID, *NetworkBuffer, 2048 )
  Header = PeekB(*NetworkBuffer)
  Select Header
     Case #Network_MessagePacket
         ;code for handling packets of "message" type here

     Case #Network_PingPacket
         ;code for handling packets of "ping" type here

     Case #Network_HelloPacket
         ;code for handling packets of "hello" type here
  EndSelect
EndProcedure
So now comes the question: Does RecieveNetworkData receive all the bytes I have sent with the client? Or can it receive for example half of my "packet" (yes I know TCP doesn't use packets). RecieveNetworkData should return amount of bytes recieved, but how can I ensure that this is all the data I am expecting? (the client might already sending more data!)

Re: Network Question

Posted: Mon May 09, 2011 6:20 pm
by Comtois
http://www.purebasic.com/documentation/ ... kdata.html
Result = ReceiveNetworkData(Connection, *DataBuffer, DataBufferLength)
You should test Result in a loop
The 'Result' returns the number of bytes effectively read. If 'Result' is equal to DataBufferLength, then more data is available to be read. If an error occured on the connection (link broken, connection close by the server etc.), 'Result' will be -1.

Re: Network Question

Posted: Mon May 09, 2011 8:04 pm
by Zefz
Yes that is what I thought. But does each RecieveNetworkData only contain data from a specific SendNetworkData? Or is it possible that it also contains some bytes from a whole different SendNetworkData that has nothing to do with this batch of data? (if so, that would be strange, since TCP is supposed to deliver in order service)

So according to you this should work:

Code: Select all

Result = 0
While Result <> DataBufferLength
  Result + ReciveNetworkData(Connection, *Buffer, Length)
Wend

Re: Network Question

Posted: Tue May 10, 2011 6:43 am
by Nituvious
the network library isn't threadsafe?

Re: Network Question

Posted: Tue May 10, 2011 1:25 pm
by auser
Zefz wrote:Yes that is what I thought. But does each RecieveNetworkData only contain data from a specific SendNetworkData?
As far I've found out myself it even read data from a following SendNetworkData at once but would get it serial and not mixed up. So if you send always a header (for example one "byte.b " if you never use more then 256 bytes or better one "unicode.u" if you send up to 65536 bytes) that is telling your program how much data it have to read until the next packet starts you can handle that. You can even create a list with a structure that buffer that data from different clients and let your network function just answer something back if the packet is finished.


Code: Select all

Result = 0
While Result <> DataBufferLength
  Result + ReciveNetworkData(Connection, *Buffer, Length)
Wend
I would not recommend to do it that way but always use just one ReceiveNetworkData() after a Network[Client/Server]Event (even if he still need more data).

Nituvious wrote: the network library isn't threadsafe?
As far I know it's not threadsafe - but in the german forum there is a lib that extend the PB-functionts to make them threadsafe.


Greetings...

Re: Network Question

Posted: Tue May 24, 2011 6:01 pm
by RichAlgeni
The network is thread safe, but you can never guarantee that you will get an entire 'packet' on each read. You many get half, or you may get two packets. (Packet is a term many will use in regards to TCP.) We we write an interface, we usually include start and stop bytes, such as <stx> (02h) and <etx> (03h). From there it's just a matter of parsing.

You won't get a '#PB_NetworkEvent_Connect' if there is more data in the buffer, so exhaust the buffer until you get 0 bytes returned.

Remember to always free you memory, if you allocate memory in a procedure.

If you need specific examples, just ask, the folks on this board are great!

Re: Network Question

Posted: Tue May 24, 2011 9:26 pm
by Nituvious
RichAlgeni wrote:The network is thread safe, but you can never guarantee that you will get an entire 'packet' on each read. You many get half, or you may get two packets. (Packet is a term many will use in regards to TCP.) We we write an interface, we usually include start and stop bytes, such as <stx> (02h) and <etx> (03h). From there it's just a matter of parsing.

You won't get a '#PB_NetworkEvent_Connect' if there is more data in the buffer, so exhaust the buffer until you get 0 bytes returned.

Remember to always free you memory, if you allocate memory in a procedure.

If you need specific examples, just ask, the folks on this board are great!
Nice tips. If you use UDP you won't get a #PB_NetworkEvent_Connect or #PB_NetworkEvent_Disconnect.
One question on TCP though, I thought TCP didn't generally use packets but was more of a stream of data so you wouldn't have data loss?

Re: Network Question

Posted: Tue May 24, 2011 11:12 pm
by RichAlgeni
You're right Nituvious, it certainly is a stream, the network will stream data into you as it becomes available. But since we read the data as groups of bytes, it's not uncommon to call those groups packets. Especially if you are interfacing to another program where data is read, acted upon, then data is sent back. Sometimes we use start and stop bytes, so we know when we have a complete packet. Other times it could be message length, where for instance each packet is 80 bytes. Because sockets are a 'stream' connection, it's possible that we could receive 80, 120, 160 or more bytes in each socket read. In this case we would have to parse the data to find our packets, then save the remainder for the next packet.

If we're talking about the web, the whole page could be considered a packet. But we can't count on the entire page coming in on one read, unless the server is on the same subnet. Even then we can't say with certainty that all of the data will come through in one read. That's why we loop when reading a socket, until there is no more left to read.

There are many of us who have written procedures just for this, with multiple tries, and a timeout. That way if noting is received within a certain time, the procedure will return, and the program can continue. I actually have two, one for ASCII data, and one for binary.

Rich

Re: Network Question

Posted: Wed May 25, 2011 12:06 am
by Nituvious
RichAlgeni wrote:You're right Nituvious, it certainly is a stream, the network will stream data into you as it becomes available. But since we read the data as groups of bytes, it's not uncommon to call those groups packets. Especially if you are interfacing to another program where data is read, acted upon, then data is sent back. Sometimes we use start and stop bytes, so we know when we have a complete packet. Other times it could be message length, where for instance each packet is 80 bytes. Because sockets are a 'stream' connection, it's possible that we could receive 80, 120, 160 or more bytes in each socket read. In this case we would have to parse the data to find our packets, then save the remainder for the next packet.

If we're talking about the web, the whole page could be considered a packet. But we can't count on the entire page coming in on one read, unless the server is on the same subnet. Even then we can't say with certainty that all of the data will come through in one read. That's why we loop when reading a socket, until there is no more left to read.

There are many of us who have written procedures just for this, with multiple tries, and a timeout. That way if noting is received within a certain time, the procedure will return, and the program can continue. I actually have two, one for ASCII data, and one for binary.

Rich
A network guru! :shock:
I have SOOO many questions for you!

Re: Network Question

Posted: Wed May 25, 2011 2:00 am
by RichAlgeni
Question away, I haven't got a lot of time in with PB, but I do have a lot of time in networks.
:)