Module NetworkTCP - Send and Receive Data over 64kB

Share your advanced PureBasic knowledge/code with the community.
User avatar
mk-soft
Always Here
Always Here
Posts: 6201
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Module NetworkTCP - Send and Receive Data over 64kB

Post by mk-soft »

I don't know it works with sock stream

Update v1.01.2
- macOS constant

Code: Select all

;-TOP by mk-soft, v1.01.2, 23.04.2023

; Only TCP/IP
; Len = CheckReceiveLength(ConnectionID(Client))

CompilerSelect #PB_Compiler_OS
  CompilerCase #PB_OS_Linux
    #FIONREAD = $0000541B
  CompilerCase #PB_OS_MacOS
    #FIONREAD = $4004667F
CompilerEndSelect

Procedure CheckReceiveLength(Socket)
  Protected length, result
  
  CompilerSelect #PB_Compiler_OS
    CompilerCase #PB_OS_Windows
      result = ioctlsocket_(Socket, #FIONREAD, @length)
      
    CompilerCase #PB_OS_Linux
      result = ioctl_(Socket, #FIONREAD, @length)
      
    CompilerCase #PB_OS_MacOS
      result = ioctl_(Socket, #FIONREAD, @length)
      
  CompilerEndSelect
  
  If result <> 0
    ProcedureReturn -1; socket error
  EndIf
  
  ProcedureReturn length
EndProcedure
Last edited by mk-soft on Sun Apr 23, 2023 1:48 pm, edited 1 time in total.
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
skinkairewalker
Enthusiast
Enthusiast
Posts: 772
Joined: Fri Dec 04, 2015 9:26 pm

Re: Module NetworkTCP - Send and Receive Data over 64kB

Post by skinkairewalker »

its works with UDP ?
User avatar
mk-soft
Always Here
Always Here
Posts: 6201
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Module NetworkTCP - Send and Receive Data over 64kB

Post by mk-soft »

Update v1.01.2
- macOS constant
skinkairewalker wrote: Fri Apr 21, 2023 7:08 pm its works with UDP ?
No, only tcp/ip
Perhaps with recv(socket, ...) with peek
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
skinkairewalker
Enthusiast
Enthusiast
Posts: 772
Joined: Fri Dec 04, 2015 9:26 pm

Re: Module NetworkTCP - Send and Receive Data over 64kB

Post by skinkairewalker »

I tried to use it with the atomic web server, but I don't know how to make it work...

Code: Select all



CompilerIf #PB_Compiler_Thread = 0
  CompilerError "Use Compileroption Threadsafe!"
CompilerEndIf

EnableExplicit

IncludeFile "NetworkFunctions.pb"

Global Title.s = "Atomic Web Server v2.0"

Global Port = 6833

Global WWWDirectory.s = "www/"
Global WWWIndex.s = "index.html"
Global WWWError.s = "error.html"

Global BufferSize = 1024, *Buffer = AllocateMemory(BufferSize), Buffer.s

Global ClientID

Declare Start()                                                 
Declare ProcessRequest()                                         
Declare BuildRequestHeader(*Buffer, DataLength, ContentType.s)  
Declare Resize()
Declare Exit()                                                  

Start()

;Affichage / Show application
Procedure Start()
  Protected ServerEvent, Result
  
  If Not InitNetwork() 
    MessageRequester(Title, "Can't initialize the network !", 0)
  Else     
    
    ;Création du serveur / Create server 
    If CreateNetworkServer(0, Port)      
      OpenWindow(0, 0, 0, 800, 600, Title, #PB_Window_SystemMenu | #PB_Window_SizeGadget)
      EditorGadget(0, 0, 0, 800, 560, #PB_Editor_ReadOnly)
      AddGadgetItem(0, -1, "Server listening on port " + Port)
      
      CheckBoxGadget(1, 10, 570, 200, 22, "Show Log") 
      SetGadgetState(1, #PB_Checkbox_Checked)
      
      ;Déclencheur / Trigger
      BindEvent(#PB_Event_SizeWindow, @Resize())
      BindEvent(#PB_Event_CloseWindow, @Exit())
      
      Repeat    
        Repeat : Until WindowEvent() = 0
        
        ServerEvent = NetworkServerEvent()
        If ServerEvent
          ClientID = EventClient()
          Buffer = ""
          Select ServerEvent              
            Case #PB_NetworkEvent_Data 
              Repeat
                FreeMemory(*Buffer)
                *Buffer = AllocateMemory(BufferSize)
                Result = ReceiveNetworkData(ClientID, *Buffer, BufferSize)
                Buffer + PeekS(*Buffer, -1, #PB_UTF8)
              Until Result <> BufferSize
              
              ProcessRequest()
          EndSelect
        Else
          Delay(10)  ; Ne pas saturer le CPU / Don't stole the whole CPU !
        EndIf
      ForEver     
    Else
      MessageRequester(Title, "Error: can't create the server (port " + port + " in use ?)")
    EndIf
  EndIf
EndProcedure

;Demande de traitement / Process Request
Procedure ProcessRequest()
  Protected RequestedFile.s, FileLength, MaxPosition, Position, ContentType.s
  Protected *FileBuffer
  Protected BufferOffset.s, *BufferOffset
  
  If Left(Buffer, 3) = "GET"    
    ;Extract page html from GET /yourpage.html HTTP/1.1
    MaxPosition = FindString(Buffer, Chr(13), 5)
    Position = FindString(Buffer, " ", 5)
    If Position < MaxPosition
      RequestedFile = Mid(Buffer, 6, Position-5)      ; Automatically remove the leading '/'
      RequestedFile = RTrim(RequestedFile)
    Else
      RequestedFile = Mid(Buffer, 6, MaxPosition-5)   ; When a command like 'GET /' is sent..
    EndIf
    
    If RequestedFile = ""
      RequestedFile = WWWIndex      
    EndIf
    
    ;Mise à jour du log / UPdated log
    If GetGadgetState(1) = #PB_Checkbox_Checked
      AddGadgetItem(0, -1, "Client IP " + IPString(GetClientIP(ClientID)) + " load " + RequestedFile) 
    EndIf   
      
    ;Envoyer la page HTML au client / Send the HTML page to the client
    If ReadFile(0, WWWDirectory + RequestedFile)
      
      ;Préparation de la page HTML à envoyer
      FileLength = Lof(0)
      
      ;Definition du content-type / Setup content-type
      ;Ref : https://fr.wikipedia.org/wiki/Type_MIME
      Select GetExtensionPart(RequestedFile)
        Case "css" : ContentType = "text/css"
        Case "js"  : ContentType = "application/javascript" 
        Case "gif" : ContentType = "image/gif"
        Case "jpg" : ContentType = "image/jpeg"
        Case "png" : ContentType = "image/png"
        Case "txt" : ContentType = "text/plain"
        Case "zip" : ContentType = "application/zip"
        Case "pdf" : ContentType = "application/pdf"
          
        Default     
          ContentType = "text/html" 
      EndSelect      
      
    Else
      
      ;Affichage de la page d'erreur si url inexistant / Display error page if url nonexistent
      If ReadFile(0, WWWDirectory + WWWError, #PB_UTF8)
        FileLength = Lof(0)
        ContentType = "text/html"        
      EndIf
    EndIf
    
    ;Envoie des données au client / Sends data to the client
    *FileBuffer   = AllocateMemory(FileLength + 200)
    *BufferOffset = BuildRequestHeader(*FileBuffer, FileLength, ContentType)
    ReadData(0, *BufferOffset, FileLength)
    CloseFile(0)
    
    If (MemorySize(*FileBuffer) <= 65536)
      
      SendNetworkData(ClientID, *FileBuffer, *BufferOffset - *FileBuffer + FileLength)
      
    Else  
      
    NetworkTCP::TcpSendData(ClientID,*FileBuffer,MemorySize(*FileBuffer)) ; <--------------------------- HEREEEE
    
    EndIf 
    
    FreeMemory(*FileBuffer)
  EndIf  
EndProcedure

;Creation entete HTTP / Create HTTP header
Procedure BuildRequestHeader(*FileBuffer, FileLength, ContentType.s)
  Protected Length
  Protected Week.s = "Sun, Mon,Tue,Wed,Thu,Fri,Sat"
  Protected MonthsOfYear.s = "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec" 
  
  Protected DayOfWeek.s = StringField("Sun, Mon,Tue,Wed,Thu,Fri,Sat", DayOfWeek(Date()) + 1, ",")
  Protected Day = Day(Date())
  Protected Month.s = StringField("Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec", Month(Date()), ",")
  Protected Year.s = Str(Year(Date()))
  Protected Time.s = FormatDate("%hh:%ii:%ss GMT", Date())
  
  Length = PokeS(*FileBuffer, "HTTP/1.1 200 OK" + #CRLF$, -1, #PB_UTF8)                                                             : *FileBuffer + Length
  Length = PokeS(*FileBuffer, "Date: " + DayOfWeek + ", " + Day + " " + Month + " " + Year + " " + Time  + #CRLF$, -1, #PB_UTF8)    : *FileBuffer + Length
  Length = PokeS(*FileBuffer, "Server: "+ Title + #CRLF$, -1, #PB_UTF8)                                                             : *FileBuffer + Length
  Length = PokeS(*FileBuffer, "Content-Length: " + Str(FileLength) + #CRLF$, -1, #PB_UTF8)                                          : *FileBuffer + Length
  Length = PokeS(*FileBuffer, "Content-Type: " + ContentType + #CRLF$, -1, #PB_UTF8)                                                : *FileBuffer + Length
  Length = PokeS(*FileBuffer, #CRLF$, -1, #PB_UTF8)                                                                                 : *FileBuffer + Length
  
  ProcedureReturn *FileBuffer
EndProcedure

Procedure Resize()
  Protected Width = WindowWidth(0)
  Protected Height = WindowHeight(0)
  
  ResizeGadget(0, #PB_Ignore, #PB_Ignore, Width, Height-40)
  ResizeGadget(1, #PB_Ignore, Height - 30, #PB_Ignore, #PB_Ignore)
EndProcedure


;Sortie  / Exit 
Procedure Exit()
  CloseNetworkServer(0)  
  End
EndProcedure

Is there any way to make it work to send packages of sites and assets larger than 64kb?
User avatar
RichAlgeni
Addict
Addict
Posts: 935
Joined: Wed Sep 22, 2010 1:50 am
Location: Bradenton, FL

Re: Module NetworkTCP - Send and Receive Data over 64kB

Post by RichAlgeni »

skinkairewalker wrote: Mon May 15, 2023 4:28 am Is there any way to make it work to send packages of sites and assets larger than 64kb?
What exactly are you trying to do? the 64 KB packet limitation is an absolute limit. However, you can send as much data as you would like, if you use something like this:

Code: Select all

EnableExplicit

Define result.i
Define someHost.s
Define somePort.l
Define *memoryLoc
Define largeSize.l
Define totalSent.l
Define lenSendText.l
Define socketNumber.l

largeSize = 2000000

*memoryLoc = AllocateMemory(largeSize)

RandomData(*memoryLoc, largeSize)

lenSendText = largeSize

socketNumber = OpenNetworkConnection(someHost, somePort)

If socketNumber > 0
    While lenSendText > 0
        result = SendNetworkData(socketNumber, *memoryLoc + totalSent, lenSendText)

; if we've received an error, record it, close the socket, and set the condition to exit the loop

        If result < 0
            totalSent   = result
            CloseNetworkConnection(socketNumber)
            lenSendText = 0
        Else
            totalSent   = totalSent   + result
            lenSendText = lenSendText - result
        EndIf
    Wend
EndIf
The SendNetworkData function will return to you the number of bytes that were actually sent. Add that to you next send, to get the next set of bytes to send. Continue this until you are done.
infratec
Always Here
Always Here
Posts: 7575
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Module NetworkTCP - Send and Receive Data over 64kB

Post by infratec »

I already told him this. :wink:
User avatar
RichAlgeni
Addict
Addict
Posts: 935
Joined: Wed Sep 22, 2010 1:50 am
Location: Bradenton, FL

Re: Module NetworkTCP - Send and Receive Data over 64kB

Post by RichAlgeni »

infratec wrote: Fri May 19, 2023 3:42 pm I already told him this. :wink:
:D :D :D
User avatar
mk-soft
Always Here
Always Here
Posts: 6201
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Module NetworkTCP - Send and Receive Data over 64kB

Post by mk-soft »

Update v1.21.4
- Rename structures
- Changed query data complete
- Changed default data block size

Changed query data completely.

It is no longer queried whether the last data block has arrived, but whether all have arrived.
It can also happen that a data block arrives a little too late via a diversion through another router. But this can occur very rarely.

Set the standard data block size (including header) to 128 kb. For old systems, however, it should be set to 64kb.
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
FlorenceF
New User
New User
Posts: 3
Joined: Fri Jan 17, 2025 6:58 pm

Re: Module NetworkTCP - Send and Receive Data over 64kB

Post by FlorenceF »

Hello

How to get receive progress ?
User avatar
RichAlgeni
Addict
Addict
Posts: 935
Joined: Wed Sep 22, 2010 1:50 am
Location: Bradenton, FL

Re: Module NetworkTCP - Send and Receive Data over 64kB

Post by RichAlgeni »

The only way to get the receive process to know how many bytes are sent, is to send the number of bytes you will send at the beginning of the data. You can do this by sending a fixed number of bytes, for instance 6 (which can give you up to 999,999 ascii bytes in length), or use a character separator to separate the length from the rest of the data. Once you have the total length that is being sent to you, it's just an easy division of bytes received divided by total length.

You can get the number of bytes available in the read buffer using the following code:

Code: Select all

Define length.l
Define result.i
Define socketHandle.i
Define socketNumber.i
socketHandle = ConnectionID(socketNumber)
result       = ioctlsocket_(socketHandle, #FIONREAD, @length)
Note that depending on the amount of data sent, you may receive it in one read, or multiple reads, even if there less than 64K bytes sent. If you have the number of bytes you need, you can then use ReceiveNetworkData() to get only the amount of bytes needed for your particular packet. Your next read will be a new packet, with a new byte length.

I prefer the fixed number of bytes to get the length of ascii bytes. That way, you can always read that amount in, to get the rest of the data you need.
User avatar
RichAlgeni
Addict
Addict
Posts: 935
Joined: Wed Sep 22, 2010 1:50 am
Location: Bradenton, FL

Re: Module NetworkTCP - Send and Receive Data over 64kB

Post by RichAlgeni »

Take a look at my network procedure, Let me know if you have any questions.

Code: Select all

; Program name: network_procs.pbi
; Written by:   Rich Algeni, Jr.
; Date written: 02/17/2011
;
; Purpose: to include network procedures into PB programs
; ------------------------------------------------------------

Global maxUDPLength.i =  2048
Global maxTCPLength.i = 65535

Declare.i CloseNetworkSocket(*socketNumber)
Declare.i SetTCPBufferSize(*socketNumber, bufferSize.i = maxTCPLength)
Declare.i SetServerSocketTimeout(*socketNumber, bufferSize.i = maxTCPLength)
Declare.i OpenClientSocket(*serverName, serverPortNumber.i, *errorReturn, bufferSize.i = maxTCPLength, networkMode.i = #PB_Network_TCP, openTimeout.i = 5000)
Declare.i NetworkWrite(*socketNumber, *errorReturn, *memoryLoc, lenSendText.i, *netSource, debugThis.i)
Declare.i NetworkRead(*socketNumber, *errorReturn, *memoryLoc, memLength.i, *netSource, debugThis.i, socketTimeout.i, maxReadTrys.i)
Declare.i NetworkReadFixed(*socketNumber, *errorReturn, *memoryLoc, memLength.i, *netSource, debugThis.i, socketTimeout.i, maxReadTrys.i)
Declare.i CleanNetworkInputBuffer(*socketNumber, *errorReturn)
Declare.i NetworkInputBufferAmount(*socketNumber, *errorReturn)
Declare.i NetworkUDPRead(*socketNumber, *errorReturn, *memoryLoc, memLength.i, *netSource, debugThis.i, socketTimeout.i, maxReadTrys.i)

; constant for keepalive function values

#SIO_KEEPALIVE_VALS = 2550136836

; Argument Structure For SIO_KEEPALIVE_VALS

Structure TCP_KEEPALIVE
    onOff.l
    keepAliveTime.l
    keepAliveInterval.l
EndStructure

; **********************************************************************************
; initialization of networking variables
; **********************************************************************************

Procedure.i InitializeNetwork()

; add this program name and version to the list of includes the main program is running

    AddElement(programList())
    programList() = "network_procs.pbi"

    AddElement(progVersions())
    progVersions() = "7.0.01a"

EndProcedure

; **********************************************************************************
; this procedure attempts to close the network connection via the socket handle
; **********************************************************************************

Procedure.i CloseNetworkSocket(*socketNumber)

    Protected result.l       = 0; winsock utlizes a 32 bit integer only!
    Protected socketNumber.i = PeekI(*socketNumber)
    Protected socketHandle.i

    If socketNumber > 0
        socketHandle = ConnectionID(socketNumber)

        result = closesocket_(socketHandle)
        If  result <> 0
            result = WSAGetLastError_()
        EndIf
    EndIf

    PokeI(*socketNumber, 0)

; this should return 0 if all went ok, per Microsoft

    ProcedureReturn result

EndProcedure

; **********************************************************************************
; this procedure set the TCP receive buffer size, and keepalive
; **********************************************************************************

Procedure.i SetTCPBufferSize(socketNumber.i, bufferSize.i = maxTCPLength)

    Protected result.l;    winsock utlizes a 32 bit integer only!
    Protected keepAlive.i
    Protected socketHandle.i

; if we already have an error encountered, or we don't have a socket, just return

    If socketNumber < 1 Or bufferSize < 1
        ProcedureReturn -999
    EndIf

    socketHandle = ConnectionID(socketNumber)

; version 2.3.01b, set the buffer size, the keep alive and no delay options

    If socketHandle > 0
        result = setsockopt_(socketHandle, #SOL_SOCKET, #SO_RCVBUF, @bufferSize, SizeOf(bufferSize))
    Else
        result = -1
    EndIf

; set the keepalive option and the no delay ack option, if result = 0 per Microsoft, all should be ok!

    keepAlive = #True
    If result = 0
        result = setsockopt_(socketHandle, #SOL_SOCKET, #SO_KEEPALIVE, @keepAlive, SizeOf(keepAlive))
        If result = 0
            result = setsockopt_(socketHandle, #IPPROTO_TCP, #TCP_NODELAY, @keepAlive, SizeOf(keepAlive))
            If result <> 0
                result = WSAGetLastError_()
            EndIf
        Else
            result = WSAGetLastError_()
            CloseNetworkSocket(*socketNumber)
        EndIf
    Else
        result = WSAGetLastError_()
    EndIf

; this should return 0 if all went ok, per Microsoft

    ProcedureReturn result

EndProcedure

; **********************************************************************************
; this procedure sets a server socket's keepalive and timeout values
; **********************************************************************************

; !!!!!!!!!!! this is for a server socket !!!!!!!!!!!!!

Procedure.i SetServerSocketTimeout(serverNumber.i, bufferSize.i = maxTCPLength)

    Protected result.l;              winsock utlizes a 32 bit integer only!
    Protected socketHandle.i
    Protected bytesReturned.i
    Protected alive.TCP_KEEPALIVE

; if we already have an error encountered, or we don't have a socket, just return

    If serverNumber < 1 Or bufferSize < 1
        ProcedureReturn -999
    EndIf

    socketHandle = ConnectionID(serverNumber)

; see for more info on keepalive:             https://msdn.microsoft.com/en-us/library/windows/desktop/dd877220%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396

    alive\onOff                 = 1;              If the onOff entry is set to a nonzero value, TCP keep-alive is enabled and the other members in the structure are used.
    alive\keepAliveTime         = 1000 * 60;      The keepalivetime entry specifies the timeout, in milliseconds, with no activity until the first keep-alive packet is sent.
    alive\keepAliveInterval     = 1000 * 10;      The keepaliveinterval entry specifies the interval, in milliseconds, between when successive keep-alive packets are sent if no acknowledgement is received.

; turn on keep alive for the server socket

    result = SetTCPBufferSize(serverNumber, bufferSize)
    If  result = 0
        result = WSAIoctl_(socketHandle, #SIO_KEEPALIVE_VALS, @alive, SizeOf(alive), #Null, 0, @bytesReturned, #Null, #Null)
    EndIf

; if this procedure completes successfully, the WSAIoctl function returns zero

    ProcedureReturn result

EndProcedure

; **********************************************************************************
; process to open a client socket connection, and set the receive buffer size
; **********************************************************************************

Procedure.i OpenClientSocket(*serverName, serverPortNumber.i, *errorReturn, bufferSize.i = maxTCPLength, networkMode.i = #PB_Network_TCP, openTimeout.i = 5000)

    Protected result.l; winsock utlizes a 32 bit integer only!
    Protected serverName.s
    Protected socketNumber.i
    Protected sErrorNumber.i

; attempt to open the socket here

    serverName   = PeekS(*serverName)
    socketNumber = OpenNetworkConnection(serverName, serverPortNumber, networkMode, openTimeout)

; if the socket opened successfully, set the receive buffer size

    If socketNumber > 0
        If networkMode = #PB_Network_TCP
            result = SetTCPBufferSize(@socketNumber, bufferSize)
            If result <> 0
                socketNumber = -2
                sErrorNumber = WSAGetLastError_()
                PokeI(*errorReturn, sErrorNumber)
                CloseNetworkSocket(@socketNumber)
            EndIf
        EndIf
    Else
        socketNumber = 0
        sErrorNumber = WSAGetLastError_()
        PokeI(*errorReturn, sErrorNumber)
    EndIf

; this procedure returns the socket number if the socket is open, the socket number is also Poked into *socketNumber

    ProcedureReturn socketNumber

EndProcedure

; **********************************************************************************
; this procedure returns the amount of data in the network input buffer, but nothing is returned
; **********************************************************************************

Procedure.i NetworkInputBufferAmount(*socketNumber, *errorReturn)

    Protected socketNumber.i = PeekI(*socketNumber)
    Protected length.i       = 0
    Protected result.l       = 0; winsock utlizes a 32 bit integer only!
    Protected returnAmount.i = 0
    Protected sErrorNumber.i = PeekI(*errorReturn)
    Protected socketHandle.i
    Protected logText.s

; see if we have previously encountered an error

    If sErrorNumber <> 0
        ProcedureReturn -896
    EndIf

; if we already have an error encountered, just return

    If socketNumber < 1
        logText = "Invalid Socket number " + Str(socketNumber)
        WriteToLog(@logText)
        sErrorNumber = -899
        PokeI(*errorReturn, sErrorNumber)
        ProcedureReturn sErrorNumber
    EndIf

    socketHandle = ConnectionID(socketNumber)
    result       = ioctlsocket_(socketHandle, #FIONREAD, @length)

    If result = 0
        returnAmount = length
    Else
        sErrorNumber = WSAGetLastError_()
        PokeI(*errorReturn, sErrorNumber)
        CloseNetworkSocket(*socketNumber)
        logText      = "Socket error " + Str(sErrorNumber)
        WriteToLog(@logText)

        returnAmount = -898
    EndIf

    ProcedureReturn returnAmount

EndProcedure

; **********************************************************************************
; this procedure writes data to a socket, can be used with TCP or UDP!
; **********************************************************************************

Procedure.i NetworkWrite(*socketNumber, *errorReturn, *memoryLoc, lenSendText.i, *netSource, debugThis.i)

    Protected result.l       = 0; winsock utlizes a 32 bit integer only!
    Protected totalSent.i    = 0
    Protected socketNumber.i = PeekI(*socketNumber)
    Protected sErrorNumber.i = PeekI(*errorReturn)
    Protected logText.s

; see if we have previously encountered an error

    If sErrorNumber <> 0
        ProcedureReturn -896
    EndIf

should I make a structure for sockets?

; make sure the socket is valid!

    result = NetworkInputBufferAmount(*socketNumber, *errorReturn)

; make sure our parameters are valid!

    If result < 0
        logText = "Socket " + Str(socketNumber) + " is not a valid socket"
        WriteToLog(@logText)
        ProcedureReturn -999
    EndIf
    If *memoryLoc < 1
        logText = "Pointer *memoryLoc is invalid"
        WriteToLog(@logText)
        ProcedureReturn -998
    EndIf
    If lenSendText < 1
        logText = "lenSendText is " + Str(lenSendText) + ", must be reater than 0"
        WriteToLog(@logText)
        ProcedureReturn -997
    EndIf
    If *netSource < 1
        logText = "Pointer *netSource is invalid"
        WriteToLog(@logText)
        ProcedureReturn -996
    EndIf

; try to send the data, loop until all done, or error encountered

    While lenSendText > 0
        result = SendNetworkData(socketNumber, *memoryLoc + totalSent, lenSendText)

; if we've received an error, record it, close the socket, and set the condition to exit the loop

        If result < 0
            totalSent    = result
            sErrorNumber = WSAGetLastError_()
            PokeI(*errorReturn, sErrorNumber)
            CloseNetworkSocket(*socketNumber)
            lenSendText = 0
        Else
            totalSent   = totalSent   + result
            lenSendText = lenSendText - result
        EndIf

; send the data we have transmitted to the debugger listing, or if needed the error

        If debugThis
            DebugString(*memoryLoc + totalSent, result, *netSource, #debugOut, sErrorNumber, #Null)
        EndIf
    Wend

    ProcedureReturn totalSent

EndProcedure

; **********************************************************************************
; this procedure reads binary data from a network connection in one read attempt
; **********************************************************************************

Procedure.i NetworkRead(*socketNumber, *errorReturn, *memoryLoc, memLength.i, *netSource, debugThis.i, socketTimeout.i, maxReadTrys.i)

    Protected socketNumber.i = PeekI(*socketNumber)
    Protected attemptCount.i = 0
    Protected amountRead.i   = 0
    Protected length.l       = 0
    Protected sErrorNumber.i = PeekI(*errorReturn)
    Protected logText.s

; see if we have previously encountered an error

    If sErrorNumber <> 0
        ProcedureReturn -895
    EndIf

; make sure our parameters are valid!

    If *memoryLoc < 1
        logText = "Pointer *memoryLoc is invalid"
        WriteToLog(@logText)
        ProcedureReturn -995
    EndIf
    If memLength < 1
        logText = "memLength is " + Str(memLength) + ", must be reater than 0"
        WriteToLog(@logText)
        ProcedureReturn -994
    EndIf
    If *netSource < 1
        logText = "Pointer *netSource is invalid"
        WriteToLog(@logText)
        ProcedureReturn -993
    EndIf

; loop until we have received data, or our timeout has been exceeded

    While amountRead = 0
        length = NetworkInputBufferAmount(*socketNumber, *errorReturn)

; if we encountered a socket error, exit the loop

        If length < 0
            amountRead   = -1
            sErrorNumber = PeekI(*errorReturn)

; if nothing has been received, increment the attempt counter and sleep, else get out of the loop

        ElseIf length = 0
            attemptCount = attemptCount + 1

; if maxReadTrys < 0 (-1), then reads will attempt forever, only returning if data was received, or shutdown = true

            If maxReadTrys > 0 And attemptCount > maxReadTrys
                Break
            Else
                Delay(socketTimeout)
            EndIf

; else get the data in the network receive buffer, but only up to the amount we have buffered for

        Else
            If length > memLength
                amountRead = ReceiveNetworkData(socketNumber, *memoryLoc, memLength)
            Else
                amountRead = ReceiveNetworkData(socketNumber, *memoryLoc, length)
            EndIf
            If  amountRead < 0
                sErrorNumber = WSAGetLastError_()
                PokeI(*errorReturn, sErrorNumber)
                CloseNetworkSocket(*socketNumber)
            EndIf
        EndIf

; send the data we have read to the debugger listing, if needed

        If debugThis
            DebugString(*memoryLoc, amountRead, *netSource, #debugIn, sErrorNumber, #Null)
        EndIf
    Wend

; now return the amount we have received, if anything

    ProcedureReturn amountRead

EndProcedure

; **********************************************************************************
; this procedure reads fixed amount of binary data from a network connection
; **********************************************************************************

Procedure.i NetworkReadFixed(*socketNumber, *errorReturn, *memoryLoc, memLength.i, *netSource, debugThis.i, socketTimeout.i, maxReadTrys.i)

    Protected socketNumber.i = PeekI(*socketNumber)
    Protected attemptCount.i = 0
    Protected amountRead.i   = 0
    Protected length.i       = 0
    Protected result.i       = 0
    Protected sErrorNumber.i = PeekI(*errorReturn)
    Protected logText.s

; see if we have previously encountered an error

    If sErrorNumber <> 0
        ProcedureReturn -895
    EndIf

; make sure our parameters are valid!

    If *memoryLoc < 1
        logText = "Pointer *memoryLoc is invalid"
        WriteToLog(@logText)
        ProcedureReturn -992
    EndIf
    If memLength < 1
        logText = "memLength is " + Str(memLength) + ", must be reater than 0"
        WriteToLog(@logText)
        ProcedureReturn -991
    EndIf
    If *netSource < 1
        logText = "Pointer *netSource is invalid"
        WriteToLog(@logText)
        ProcedureReturn -990
    EndIf

; this procedure COULD read multiple packets to get the amount of data needed

; loop until we have received the predetermined amount of data, or our timeout has been exceeded

    Repeat
        length = NetworkInputBufferAmount(*socketNumber, *errorReturn)

; if we encountered a socket error, exit the loop

        If length < 0
            amountRead   = -1
            sErrorNumber = PeekI(*errorReturn)
            Break

; if nothing has been received, increment the attempt counter and sleep, else get out of the loop

        ElseIf length = 0
            attemptCount = attemptCount + 1
            If attemptCount > maxReadTrys
                Break
            Else
                Delay(socketTimeout)
            EndIf

; else get the data in the network receive buffer, but only up to the amount we have buffered for

        Else
            result = ReceiveNetworkData(socketNumber, *memoryLoc + amountRead, memLength)
            If  result     > 0
                amountRead = amountRead + result
                memLength  = memLength  - result
                If memLength = 0
                    Break
                EndIf
            Else
                sErrorNumber = WSAGetLastError_()
                PokeI(*errorReturn, sErrorNumber)
                CloseNetworkSocket(*socketNumber)
                amountRead = -1
                Break
            EndIf
        EndIf
    ForEver

; send the data we have read to the debugger listing, if needed

    If debugThis
        DebugString(*memoryLoc, amountRead, *netSource, #debugIn, sErrorNumber, #Null)
    EndIf

; now return the amount we have received, if anything

    ProcedureReturn amountRead

EndProcedure

; **********************************************************************************
; this procedure cleans out current network input buffer, nothing is returned
; **********************************************************************************

Procedure.i CleanNetworkInputBuffer(*socketNumber, *errorReturn)

    Protected socketNumber.i = PeekI(*socketNumber)
    Protected length.i       = 0
    Protected returnAmount.i = 0
    Protected sErrorNumber.i = PeekI(*errorReturn)
    Protected *memoryLoc

; see if we have previously encountered an error

    If sErrorNumber <> 0
        ProcedureReturn -894
    EndIf

    length = NetworkInputBufferAmount(*socketNumber, *errorReturn)

    If length > 0
        *memoryLoc   = AllocateMemory(length + 2)
        length       = ReceiveNetworkData(socketNumber, *memoryLoc, length)
        FreeMemory(*memoryLoc)
        returnAmount = length
    EndIf

    ProcedureReturn returnAmount

EndProcedure

; **********************************************************************************
; this procedure reads binary data from a UDP network connection in one read attempt
; **********************************************************************************

Procedure.i NetworkUDPRead(*socketNumber, *errorReturn, *memoryLoc, memLength.i, *netSource, debugThis.i, socketTimeout.i, maxReadTrys.i)

    Protected socketNumber.i = PeekI(*socketNumber)
    Protected attemptCount.i = 0
    Protected amountRead.i   = 0
    Protected length.l       = 0
    Protected sErrorNumber.i = PeekI(*errorReturn)
    Protected logText.s

; see if we have previously encountered an error

    If sErrorNumber <> 0
        ProcedureReturn -895
    EndIf

; make sure our parameters are valid!

    If *memoryLoc < 1
        logText = "Pointer *memoryLoc is invalid"
        WriteToLog(@logText)
        ProcedureReturn -995
    EndIf
    If memLength < 1
        logText = "memLength is " + Str(memLength) + ", must be reater than 0"
        WriteToLog(@logText)
        ProcedureReturn -994
    EndIf
    If *netSource < 1
        logText = "Pointer *netSource is invalid"
        WriteToLog(@logText)
        ProcedureReturn -993
    EndIf

; loop until we have received data, or our timeout has been exceeded

    While amountRead = 0

; get the data in the network receive buffer, but only up to the amount we have buffered for

        amountRead = ReceiveNetworkData(socketNumber, *memoryLoc, memLength)

        If  amountRead < 0
            sErrorNumber = WSAGetLastError_()
            PokeI(*errorReturn, sErrorNumber)
            CloseNetworkSocket(*socketNumber)

; if maxReadTrys < 0 (-1), then reads will attempt forever, only returning if data was received, or shutdown = true

        ElseIf amountRead = 0
            attemptCount = attemptCount + 1
            If maxReadTrys > 0 And attemptCount > maxReadTrys
                Break
            Else
                Delay(socketTimeout)
            EndIf
        EndIf

; send the data we have read to the debugger listing, if needed

        If debugThis
            DebugString(*memoryLoc, amountRead, *netSource, #debugIn, sErrorNumber, #Null)
        EndIf
    Wend

; now return the amount we have received, if anything

    ProcedureReturn amountRead

EndProcedure
User avatar
skinkairewalker
Enthusiast
Enthusiast
Posts: 772
Joined: Fri Dec 04, 2015 9:26 pm

Re: Module NetworkTCP - Send and Receive Data over 64kB

Post by skinkairewalker »

how can i use this?
I detected several syntax errors
User avatar
mk-soft
Always Here
Always Here
Posts: 6201
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Module NetworkTCP - Send and Receive Data over 64kB

Post by mk-soft »

Seems to be an old code for old PB version.

In addition, this does not belong to this contribution NetworkTCP
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
RichAlgeni
Addict
Addict
Posts: 935
Joined: Wed Sep 22, 2010 1:50 am
Location: Bradenton, FL

Re: Module NetworkTCP - Send and Receive Data over 64kB

Post by RichAlgeni »

skinkairewalker wrote: Mon Jan 20, 2025 8:35 pm how can i use this?
I detected several syntax errors
This is a procedure to help TEACH you how to use networking in PureBasic. Child procedures often use variables defined in calling procedures. If you have specific questions, I will be glad to help you.
User avatar
RichAlgeni
Addict
Addict
Posts: 935
Joined: Wed Sep 22, 2010 1:50 am
Location: Bradenton, FL

Re: Module NetworkTCP - Send and Receive Data over 64kB

Post by RichAlgeni »

mk-soft wrote: Mon Jan 20, 2025 10:19 pm Seems to be an old code for old PB version.
Networking really hasn't changed in the 30 years I've been writing network programs.
mk-soft wrote: Mon Jan 20, 2025 10:19 pm In addition, this does not belong to this contribution NetworkTCP
Of course it does. Under the NetworkWrite() procedure, you can send an amount of data equivalent to a 64 bit positive integer.

Really? Just because the first version I wrote was in 2011? What do you believe is out of date?
Post Reply