[S]imple [N]etwork [C]onnection win and lin 32/64-bit.

Post your FreeBASIC source, examples, tips and tricks here. Please don’t post code without including an explanation.
Post Reply
badidea
Posts: 2591
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: [S]imple [N]etwork [C]onnection win and lin 32/64-bit.

Post by badidea »

Dinosaur wrote: Status = Connection->PutData(.TxPtr,40)
'I cant check Status because program ends with the above statement.
How can that be? If I look at PutData(), it can return -1 or size (does not call end() ). It does call 'send()'. Then send() terminates your program? Sounds strange to me.

CanPut() calls FD_ISSET(), it seems to me (after some searching) that if FD_ISSET() returns true if a send() call can be made without blocking, but when calling send(), it can still fail for other reasons.
D.J.Peters
Posts: 8586
Joined: May 28, 2005 3:28
Contact:

Re: [S]imple [N]etwork [C]onnection win and lin 32/64-bit.

Post by D.J.Peters »

compile it with "-exx -g"
fbc yourcode.bas -exx -g

and run it the debuger
FreeBASIC\bin\win32\gdb.exe yourcode.exe

Joshy
D.J.Peters
Posts: 8586
Joined: May 28, 2005 3:28
Contact:

Re: [S]imple [N]etwork [C]onnection win and lin 32/64-bit.

Post by D.J.Peters »

What you ceate in a loop for every pressed key a new client and connection !!!
By the way show me your server code also if you like.

Here are how it works "pseudo code" (if I remember me right)

var server_port = cushort(1234)
var server_adr = "haha.com"
or
var server_adr = "123.123.123.123"

' one client per session !
var client = NetworkClient(server_adr, server_port)

var timeout = 5000
var connection = client.GetConnection()
while (connection=NULL) and (timeout>0)
__sleep 100 : timeout-=100
__connection = client.GetConnection()
wend
if timeout<0 then DoYourTimeoutStuff()

if connection = NULL then
__ DoYourNoServerErrorStuff()
else
__loop
____ var data_to_send_available = DoYourDataStuff(buffer,buffersize)
____if data_to_send_available then
______while not connection->canPut() : sleep 10 : wend
______var status = connection->putData(buffer, buffersize)
______if status < bufferSize then DoYourSendErrorStuff()
____else
______' no data available
______sleep 100 ' don't eat all CPU cycles
____end if
__endloop
end if
if connection then delete connection : connection = NULL

The point are there isn't a client destructor if you create a client in the same var again and again in a loop you will run out of resources !
There is no need to create a server conection for every transmission !

If you do a phone call you deal the nummber once for the complete session and not for every word you speak :-)

Joshy
Last edited by D.J.Peters on Sep 08, 2020 22:55, edited 3 times in total.
Dinosaur
Posts: 1481
Joined: Jul 24, 2005 1:13
Location: Hervey Bay (.au)

Re: [S]imple [N]etwork [C]onnection win and lin 32/64-bit.

Post by Dinosaur »

Hi All

Many thanks for the replies.
I am sorting through it today.

However because the Rfid Tag reader may only send one Tx for the whole day, is the reason I terminate the connection
after a Server read. The server keeps looking for clients trying to connect all day (and night).
There are also 3 or more readers (with their own cpu) whom may contact the server.

That is why I did not want to keep a connection to each reader open all day.

My test program calls the EthTx routine only after &h0d which is the last char sent by reader.
Then until someone swipes a tag, the client just keeps looking for Inkey.

Is the snc.bi in the first post the most updated .bi ?

Regards
D.J.Peters
Posts: 8586
Joined: May 28, 2005 3:28
Contact:

Re: [S]imple [N]etwork [C]onnection win and lin 32/64-bit.

Post by D.J.Peters »

Dinosaur wrote:Is the snc.bi in the first post the most updated .bi ?
I uploaded today a new zip file but "snc.bi" is the same I updated only the get text file example.

Today most servers don't send ASCII text as it was written in a file
it comes in chunks independent of the size of the text !

here are the part i changed in file "sncDownloadTXTFile.bas"
NOTE I read the file "test.txt" from my server only as one chunk !
if you need parsing large html or other text files you have to read many chunks !

Joshy

Code: Select all

var bChunked = iif(instr(Header,"chunked")>0,true,false)
' get first byte behind the HTTP ASCI header
var DataStart=LastChar+4
var DataSize=0
if bChunked then
  print "responce are in chunks of data ..."
  dim as string hexSize="&H"
  while instr( "0123456789abcdef",chr(response[DataStart]) )
    hexSize &= chr(response[DataStart]) : DataStart+=1
  wend  
  DataStart += 2 : DataSize = val(hexSize)
else
  ' look for "Content-Length: " in header
  var position = instr(header,CL)
  position += len(CL)-1
  var sLen = ""
  while instr( "0123456789",chr(Header[position]) )
    sLen &= chr(Header[position]):position+=1
  wend
  DataSize = val(sLen)
  print CL & sLen
end if  
Dinosaur
Posts: 1481
Joined: Jul 24, 2005 1:13
Location: Hervey Bay (.au)

Re: [S]imple [N]etwork [C]onnection win and lin 32/64-bit.

Post by Dinosaur »

Hi All

I am not sure if I am trying to do something that is not possible.
Running Gede debugger (gdb gui) I can trace the steps and the CanPut function passes all steps and returns.
None of the steps that would assign -1 get executed, although I could not see where the return value of 1 is set.

Perhaps I should explain my problem differently.
PC 1 runs Client program that wants to send data to PC 2.
PC 2 is just sitting at the Terminal prompt. No programs are running.

PC 1 manages to open a connection to PC 2 with the following 2 lines.

Code: Select all

                                var Client = NetworkClient(.TxIP,.TxPort)
                                var Connection = Client.GetConnection()
Next I expect that "Print Connection->CanPut()" prints -1
But it doesn't , it prints 1 and that is the problem.
Is it because we establised a connection even though there was NO Server program running.
Next the PutData line gets executed and creates an error.
The error is Signal SIGPIPE on the following line in snc.bi

Code: Select all

dim as integer nBytes = send(sock,pData,dSize, 0)
Regards
D.J.Peters
Posts: 8586
Joined: May 28, 2005 3:28
Contact:

Re: [S]imple [N]etwork [C]onnection win and lin 32/64-bit.

Post by D.J.Peters »

@Dino :-) do it like a man and use error checking !

You have to test is the server running / responding !
part 1:

Code: Select all

const as string IP = "127.0.0.1"
const as ushort PORT = 80
var Client = NetworkClient(IP,PORT)
var ErrCode = Client.GetLastError()
if ErrCode<>0 then
  print "error: can't create client ! " & GetNetworkErrorText(ErrCode)
  beep : sleep : end 1
end if
print "client connected with server " & IP
sleep
If no server is running
all the rest of your code makes no sense
because the socket is in error state !

Let say a server is running and response
you have to initial a communication channel !

part 2:

Code: Select all

var Connection  = Client.GetConnection()
ErrCode = Client.GetLastError()
if ErrCode<>0 then
  print "error: can't get a conection ! " & GetNetworkErrorText(ErrCode)
  beep : sleep : end 1
end if
If you ignore the error state the rest of your code is senseless.

I hope it's more clear now while error checking is important if you deal with any hardware resources.

Joshy
Dinosaur
Posts: 1481
Joined: Jul 24, 2005 1:13
Location: Hervey Bay (.au)

Re: [S]imple [N]etwork [C]onnection win and lin 32/64-bit.

Post by Dinosaur »

Hi All

Thank you for that little gem. By calling NetworkClient my problem is solved.

So basically calling CanPut does NOT verify that the Client Can PutData.
@Dino :-) do it like a man and use error checking !
Dino wrote
The code below is as usual stripped of all error checking to simplify my trouble shooting. (I can hear Joshy already)
Wasn't wrong was I.
Once again thank you for the lesson.

Regards
D.J.Peters
Posts: 8586
Joined: May 28, 2005 3:28
Contact:

Re: [S]imple [N]etwork [C]onnection win and lin 32/64-bit.

Post by D.J.Peters »

I added an new helper file "sendreceive.bi" with all needed error checking

Code: Select all

#pragma once
#define __SEND_RECEIVE__

#ifndef __SNC_BI__
 #include "snc.bi"
#endif

function SendData(connection as NetworkConnection ptr, strData as string) as integer
  if connection = NULL then 
    print "SendData no connection !"
    return -1
  end if
  var nChars = len(strData)
  if nChars<1 then
    print "SendData no data !"
    return -1
  end if
  var timeout=5000
  var ErrCode = connection->canPut()
  while ErrCode=0 andalso timeout>-1
    sleep 10,1 : timeout-=10
    ErrCode = connection->canPut()
  wend
  if timeout<0 then
    print "SendData canPut() timeout !"
    return -1
  end if
  if ErrCode<0 then
    print "SendData error: canPut() ! " & GetNetworkErrorText(ErrCode)
    return -1
  end if
  ErrCode = connection->putData(strptr(strData),nChars+1)
  if ErrCode<0 then
    print "SendData error: putData() ! " & GetNetworkErrorText(ErrCode)
    return -1
  end if
  'print "SendData " & ErrCode & " bytes sended ok"
  return 0
end function

function ReceiveData(connection as NetworkConnection ptr, strData as string, maxSize as integer=0) as integer
  if connection = NULL then 
    print "ReceiveData no connection !"
    return -1
  end if
  var timeout=5000
  var ErrCode = connection->canGet()
  while ErrCode=0 andalso timeout>-1
    sleep 10,1 : timeout-=10
    ErrCode = connection->canGet()
  wend
  if timeout<0 then
    print "ReceiveData canGet() timeout !"
    return -1
  end if
  if ErrCode<0 then
    print "ReceiveData error: canGet() ! " & GetNetworkErrorText(ErrCode)
    return -1
  end if
  dim as zstring ptr buffer=NULL
  ErrCode = connection->getData(buffer,maxSize)
  if ErrCode<0 then
    print "ReceiveData error: getData() ! " & GetNetworkErrorText(ErrCode)
    return -1
  end if
  strData=*buffer
  deallocate buffer ' allocated by "snc.bi"
  return ErrCode
end function
I added a simple server.bas and client.bas witch used the helper's from "sendreceive.bi"
Would be nice if some one can test it and report any problems.

Best way are open two console window next byside
in one execute the server at first and in the second the client.

happy coding !

Joshy
Dinosaur
Posts: 1481
Joined: Jul 24, 2005 1:13
Location: Hervey Bay (.au)

Re: [S]imple [N]etwork [C]onnection win and lin 32/64-bit.

Post by Dinosaur »

Hi All

Thanks Joshy, I will test and make a minimal TxApp & RxApp in the next few days using Desktop PC and Beaglebone.

Regards
Edit: Had to use different Port (Bind Error on Port 80) otherwise it worked using the Client.bas & Server.bas from you latest .zip file.
Will try to use the mods for my use.
I Promise I leave your error handling intact. :)
Gunslinger
Posts: 103
Joined: Mar 08, 2016 19:10
Location: The Netherlands

Re: [S]imple [N]etwork [C]onnection win and lin 32/64-bit.

Post by Gunslinger »

Hello i have tested this in the SNC in the passed.
Nicely done. only problem i had is in the function NetworkConnection.GetData(byref pData as any ptr, byval maxSize as integer) as integer
Think it is not the right way to keep waiting or delayed in this function for data to be fully revived or to timeout.
Beter to leave this function with a flag status and get the remaining data later or time out.
So the CPU can do other tasks in meantime.
D.J.Peters
Posts: 8586
Joined: May 28, 2005 3:28
Contact:

Re: [S]imple [N]etwork [C]onnection win and lin 32/64-bit.

Post by D.J.Peters »

Gunslinger wrote:Hello i have tested this in the SNC in the passed.
That gives me a smile on my face I like if some one test my hobby stuff :-)
Gunslinger wrote:Nicely done. only problem i had is in the function NetworkConnection.GetData(byref pData as any ptr, byval maxSize as integer) as integer
Think it is not the right way to keep waiting or delayed in this function for data to be fully revived or to timeout.
I don't think the same.
You have to use CanGet() and GetData() as a pair and CanPut() and PutData() as pair also !
Compared to no ScreenLock() without an ScreenUnlock() you know what I mean.

Back to GetData() if you used and you schould use CanGet() before there isn't a time out / or big delay while data are reading.
The Timeout value are only used if more data then CHUNK_SIZE (8K) available.

I found out and posted it also, there is no good default CHUNK_SIZE.
On one XP machine 4K chunks was the fasted on my Linux Server 128K and my 4 boxes at home 8 ... 32K
and Raspberry Pi and BeagleBone Black differs also.

The only way to help GetData() to do it best is you as coder knows the maximum size of data chunk you used !

For example if you transmit and received a datastructur of 32 bytes (in a game or anything with a fixed size)
it's a good idea to use the optional parameter maxSize = 32 !

In the latest version of the zip file I wrote:

Code: Select all

if maxSize>0 and maxSize<CHUNK_SIZE then
  chunkSize=maxSize
else
  chunkSize = CHUNK_SIZE ' <-- 8K
end if
...
dim as integer nBytes = recv(sock,@chunk(0),chunkSize, 0)
On other side if you download videos of 20-40 MB may be changing the const CHUNK SIZE from 8K to 16,32 ... gives a better performance.

The primary problem is (I think) while receiving data
your ISP, Modem, Router, Ethernet card, or WLAN interface doesn't know
how large will it be and you can only give the last device in this chain Ethernet or WLAN device a hint !
(but between your device and the socket interface you are using with "snc.bi" are the software layered stack also)

In real a data frame for DSL, ADSL, VDSL, TCP layer ... can be 1150 bytes or 1280 bytes or 2K ....
But this does not mean you are lucky if you use 1150 bytes or 1280 bytes or 2K also.

The size of a hardware or protocol data chunk isn't pure data it's a header, ckecksums etc. + your data as paiload !

With other words if CanGet() return a "1" there should be no big delay if you call GetData(buffer ptr, maxSize=your_hint) !

By the way you can receive data in a thread code block also.
If you got the data in a buffer you are waiting for set a global flag
(or use the any ptr thread param) for your main code and terminate the thread :-)

Bla bla bla :-)

Joshy
Dinosaur
Posts: 1481
Joined: Jul 24, 2005 1:13
Location: Hervey Bay (.au)

Re: [S]imple [N]etwork [C]onnection win and lin 32/64-bit.

Post by Dinosaur »

Hi All

Can someone tell me how to allow a longer delay for "Client = NetworkClient(.TxIP,.TxPort)"
My server is busy with other things and checks for clients only every second.
The client has at least 10 sec of spare time.

Regards
EDIT:Figured it out, doens't need time extension.
D.J.Peters
Posts: 8586
Joined: May 28, 2005 3:28
Contact:

Re: [S]imple [N]etwork [C]onnection win and lin 32/64-bit.

Post by D.J.Peters »

Dinosaur wrote:EDIT: Figured it out, doens't need time extension.
Share your solution with all of us.
(This is how a community works)

Joshy
Dinosaur
Posts: 1481
Joined: Jul 24, 2005 1:13
Location: Hervey Bay (.au)

Re: [S]imple [N]etwork [C]onnection win and lin 32/64-bit.

Post by Dinosaur »

Hi All

Sometimes I ask questions before experimenting with different solutions.
This was one of those.

The problem was that the client may at unpredictable times try to transmit the result of an rfid scan.
If the server only checks every 1,5 or even 10 seconds this line fails at the Client.

Code: Select all

 Client = NetworkClient(.TxIP,.TxPort)
Simply because the Server is not up and running. So in the server I had to run the following line at startup of program.

Code: Select all

var Shared Server = NetworkServer(Ethernet.RxPort)
Then the following code whenever I have time.

Code: Select all

Sub RxCheck
    ''Checks if Rfid tags have been swiped at Client station.
    ''First time here we check if "var shared  Server = NetworkServer(Ethernet.RxPort) in Types.bi
    ''created an error, if not then server will run all day looking for Clients every few seconds

    With Ethernet
        If .Flag = 0 Then
            .ErrCode   = Server.GetLastError()
            If .ErrCode <> 0 Then
                    .ErrMessage = GetNetworkErrorText(.ErrCode)
                    Print .ErrMessage
                    Exit Sub
                Else
                    .Flag = 1
            EndIf
        EndIf
        If connection2 = NULL Then
            connection2 = Server.GetConnection()
            If connection2 Then
               .RxData  = ""
               .ErrCode = ReceiveData(connection2,.RxData,24)
               If .ErrCode = -1 Then
                        .ErrMessage = GetNetworkErrorText(.ErrCode)
                        Print .ErrMessage
                        connection2 = NULL
                    Else
                        Dim as uShort Xq,Xy
                        Dim as String RfidFlag
                        Xq = Instr(.RxData,",")
                        If Xq > 0 Then
                            Rfid.RxTag = Mid(.RxData,Xq + 1,10)
                            For Xy = 1 to 50
                                If Rfid.RxTag = Rfid.Tag(Xy) Then
                                    If Rfid.Flag(Xy) = 0 Then Rfid.Flag(Xy) = 1 Else Rfid.Flag(Xy) = 0
                                    Exit For
                                EndIf
                            Next
                            If Rfid.Flag(Xy) = 1 Then
                                    RfidFlag = Rfid.Naam(Xy) + " arrvd @ " + Time
                                Else
                                    RfidFlag = Rfid.Naam(Xy) + " left  @ " + Time
                            EndIf
                            Print Rfid.RxTag,RfidFlag
                        EndIf
               EndIf
           EndIf
        Endif
    End With
    if connection2 <> NULL then connection2 = NULL ' disconnect
End Sub
It seems that the client succeeds in sending the Data and when I execute the above code the data is retrieved at the server.
I have not tested at 10 second interval yet, but a few seconds seem to work.
It is a long time since I wrote a Dos ethernet driver, (had a brain tumor in between) so don't remember if the hardware is handling the reception and waits for the software layer to
retrieve it.

Will persevere and test the limits.

Regards
EDIT: 10 seconds works , so perhaps the client hangs in there for that long, Joshy you may be able to tell me that.
Edit2: I sent 6 transmissions. The client takes on average 0.5 to 1.5 mSec to complete it's send.
The server took exactly 10 sec's to retrieve each one, therefore a total of 60 secs for 6 transmissions.
Post Reply