Page 1 of 1

ReceiveNetworkData

Posted: Sat Jul 05, 2008 4:25 am
by idle
I'm assuming this'll work as intended, I'm yet to test it, so feel free to edit.
Most of the examples I've seen regarding ReceiveNetworkData don't appear to take into account receiving large data streams and either assume your getting a tiny amount of data or they have an unnecessary propensity (habit) of Reallocating memory in case your getting more.

Also i think the default recv buffer in windows is 4096 bytes unless you set it to some other size.

Please correct me if I'm wrong, lectures most welcome!

Code: Select all


Procedure Listen(Dummy.l)
      
  Protected TotalBytesRead.l,BytesRead.l,*DataBuffer, bufferlen.l, bigBufferlen.l, Timeout.l,err
    
   bufferlen = 4096
   bigBufferlen = 1024*1024 ;set to some max, you may need and if you need more it'll realocate appending the bufferlen
  *DataBuffer = AllocateMemory(bufferlen)
  *BigBuffer = AllocateMemory(bigBufferlen) 
      
  While 1
   
    EventType = NetworkServerEvent()
        
    If EventType = #PB_NetworkEvent_Data
      
      TotalBytesRead = 0       
      Timeout = GetTickCount_() + 5000                 
      Repeat      ;
                   
         BytesRead = ReceiveNetworkData(EventClient(), *DataBuffer, bufferlen) 
         
         If BytesRead <> -1 
           
           If TotalBytesRead + BytesRead >= bigbufferlen 
              bigBufferlen + bufferlen 
              *tB = ReAllocateMemory(*BigBuffer,bigBufferlen)
              If *tB 
                *BigBuffer = *tb
              Else 
                ;better wave a magic wand and flush your buffer your out of memory 
              EndIf  
           EndIf 
              
           CopyMemory(*DataBuffer, *BigBuffer + TotalBytesRead, BytesRead)
           TotalBytesRead + BytesRead
           Timeout = GetTickCount_() + 5000 ;increment the time out here in case loads of WSAEWOULDBLOCK = 10035
         Else 
            err = WSAGetLastError_()  
            If err <> 10035  ;10035 temp unavailable keep trying   
              Debug "recv err = " + Str(WSAGetLastError_())      
              ;look here for err descriptions http://msdn.microsoft.com/en-us/library/ms740668(VS.85).aspx 
              ;Additionally call an error routine to determine if the error is recoverable and return the timeout else return 0 
              ;timeout = LookupWSAError(err,timeout)
            EndIf  
         EndIf 
                          
                               
      Until BytesRead = 0 Or GetTickCount_() > timeout 
      
      If BytesRead = 0 
        ;do stuff with your data 
      Else 
        ;it timed out lookup err and take some action
      EndIf 
                
   EndIf
  
   Delay(5)
  
  Wend
  
  FreeMemory(*DataBuffer)
  FreeMemory(*BigBuffer)   

EndProcedure  

senddata

Code: Select all


Procedure SendData(ip,port,*data,len)
 
Protected Tx.l, Timeout.l, Connection.l
 
  
   Connection = OpenNetworkConnection(ip, port)
   
   If Connection 
      Tx = 0
      Timeout = GetTickCount_() + 5000
      Repeat  
         Result = SendNetworkData(Connection,*data+Tx,len-Tx)   
         If Result <> -1 
             Tx = Tx + Result
             Timeout = GetTickCount_() + 5000
         Else 
            err = WSAGetLastError_()
            If err <> 10035
               ;timeout = LookupWSAerror(err,timeout)
               ;lookup error return timeout if recoverable else 0 and bail 
               Debug Str(err) 
            Endif
         EndIf  
                
      Until Tx >= len Or GetTickCount_() > Timeout 
      
      CloseNetworkConnection(Connection)
         
  EndIf 
          

EndProcedure
:wink:

Posted: Sat Jul 05, 2008 10:59 pm
by Tranquil
On Send_() or SendNetworkData() you should check for a WSAEWOULDBLOCK last error and try to send the dataset again. Maybe the send/ receivebuffers are full. This must not couse the application to stop sending datas and handling it as a fatal error.

Posted: Sun Jul 06, 2008 1:58 am
by idle
Yes you're right it should at minimum check for err 10035 WSAEWOULDBLOCK, If you look, It does have a section to check for errors, I'm just assuming people are capable to write a lookup function for themselves and follow the supplied link to msdn to read up on the errors
if the error is non recoverable then return 0 from the lookup function to bail out.

Code: Select all

if result <> -1 
  TX + Result  
else 
    err = WSAGetLastError_()
    timeout = LookUpErr(err,timeout)
endif 

Posted: Sat Aug 02, 2008 10:01 pm
by EdzUp[SD]
Surely couldnt you copy the databuffer to a string a they are 'unlimited' it would make it easier to store?

Posted: Sat Aug 02, 2008 10:41 pm
by idle
It may be easier from a users point of view to use strings, though it'll just result in it doing more reallocations behind the scenes and then a string isn't always a byte wide, which could lead to complications.

How you account for dynamic memory is more to do with the requirements for the application, it's far from optimized but it's reasonably cheap to reallocate and append a chunk only if its needed.

If you wanted to download a huge file for instance you'd probably want to use a fifo as long as you can flush it faster than you fill it, it wouldn't be a problem.

Posted: Sat Aug 02, 2008 10:57 pm
by EdzUp[SD]
ah ok always interesting in the networking side of things :)

Whats Dummy.l used for?

Posted: Sat Aug 02, 2008 11:14 pm
by idle
me of course :lol:

The procedure is set up to run as a thread, so for no particular reason I've just done what I saw others do, I don't even know if it's required to put a dummy var in, just one of those cases of monkey see and monkey do.

Posted: Sun Aug 03, 2008 1:16 pm
by EdzUp[SD]
Ah I see the variable thats passed to the function from the threading commands. If my understanding is correct you dont need a dummy variable the optional parameter in CreateThread is ignored.

Posted: Mon Aug 04, 2008 11:06 am
by Inf0Byt3
The procedure is set up to run as a thread, so for no particular reason I've just done what I saw others do, I don't even know if it's required to put a dummy var in, just one of those cases of monkey see and monkey do.
The manual says:
*Value - This is passed to the thread code as the parameter to your function. It is up to you to decide what this is used for.

Procedure YourProcedure(*Value)
; The variable '*Value' will contain 23
EndProcedure

CreateThread(@YourProcedure(), 23)
Here's a post that prooves that at least one parameter must be used:
http://www.purebasic.fr/english/viewtopic.php?t=22664

Posted: Mon Aug 04, 2008 11:53 am
by idle
@Inf0Byt3

Thanks, I should really learn to answer questions with real explanations rather than glib comments, that's the problem of having an idle mind.

Posted: Mon Aug 04, 2008 11:59 am
by Inf0Byt3
Hehe it's just you didn't meet this situation in real life. I had my share of pain with threads, it really was getting frustrating at some point.

Posted: Mon Aug 04, 2008 12:09 pm
by idle
I still have my moments, though thankfully, there's always someone willing to help and take the time to answer a question. :D

Posted: Tue Aug 05, 2008 9:09 pm
by EdzUp[SD]
I get error 10093 WSAStartup not initialised, any ideas on how to do this I am new to PB's ins and outs as it were.

Posted: Tue Aug 05, 2008 11:01 pm
by idle
No idea, what does msdn say about it?

I assume you called InitNetwork()
msdn wrote:

Successful WSAStartup not yet performed.

Either the application has not called WSAStartup or WSAStartup failed. The application may be accessing a socket that the current active task does not own (that is, trying to share a socket between tasks), or WSACleanup has been called too many times.

Posted: Wed Aug 06, 2008 11:20 am
by EdzUp[SD]
Yeah called initnetwork at the start of the test program and still 10093, I was wondering if there was something else I have to do to get the WSA system working?