QB64 Phoenix Edition
TCP/IP. data from one program to another - Printable Version

+- QB64 Phoenix Edition (https://qb64phoenix.com/forum)
+-- Forum: Chatting and Socializing (https://qb64phoenix.com/forum/forumdisplay.php?fid=11)
+--- Forum: General Discussion (https://qb64phoenix.com/forum/forumdisplay.php?fid=2)
+--- Thread: TCP/IP. data from one program to another (/showthread.php?tid=3469)

Pages: 1 2


TCP/IP. data from one program to another - TheLastTMan - 02-16-2025

hi this is my first post. really if you want you can call me Abe, short for my real name.
there is very little documentation about this and I have been experimenting on my own but have been having problems.
i recently got interested in qb64 because it looks good more than anything else, i never used the original qb. since qb64 does not support multithreading i was looking at the wiki and i think tcp/ip might be the option. it would not be multithreading but multiprocessing but something 
is something. so i have this.

Server.bas
Code: (Select All)

_TITLE "Server"
''$SCREENHIDE
REM'$CONSOLE:ONLY
'$DYNAMIC
_DEFINE A-Z AS LONG
OPTION _EXPLICITARRAY

SCREEN 0

DIM SENDEDLONGSG(1 TO 1)
DIM SENDEDFLOATG#(1 TO 1)

DIM SHARED WWW AS STRING * 3

HOST = _OPENHOST("TCP/IP:5000")
DO
    CLIENT = _OPENCONNECTION(HOST)
    IF CLIENT <> 0 THEN
        GET #CLIENT, 1, WWW$
        PRINT "SIMPLE REQUEST"
        WWW$ = UCASE$(WWW$)
        SELECT CASE WWW$
            CASE "GSL": D = UBOUND(SENDEDLONGSG): _
                    GET #CLIENT, , SENDEDLONGSG(D): PRINT SENDEDLONGSG(D):  _
                    REDIM _PRESERVE SENDEDLONGSG(D + 1) 'GAME SEND LONG"
            CASE "GRL":_
                    D = LBOUND(SENDEDLONGSG): _
                    PUT #CLIENT, , SENDEDLONGSG(D): PRINT SENDEDLONGSG(D): _
                    Z = UBOUND(SENDEDLONGSG): _
                    if Z <> D then: FOR x = 0 TO Z STEP 1: SWAP SENDEDLONGSG(D), SENDEDLONGSG(x): NEXT: _
                    REDIM _PRESERVE SENDEDLONGSG(Z - 1):  'GAME RECEIVE LONG
            CASE "GSD": D = UBOUND(SENDEDFLOATG#): _
                    GET #CLIENT, , SENDEDFLOATG#(D): _
                    REDIM _PRESERVE SENDEDFLOATG#(D + 1) 'GAME SEND DOUBLE"
            CASE "GRF":_
                    D = LBOUND(SENDEDFLOATG#): _
                    PUT #CLIENT, , SENDEDFLOATG#(D): _
                    Z = UBOUND(SENDEDFLOATG#): _
                    IF Z<>D THEN : FOR x = 0 TO Z STEP 1: SWAP SENDEDFLOATG#(D), SENDEDFLOATG#(x): NEXT: _
                    REDIM _PRESERVE SENDEDFLOATG#(Z - 1)  'GAME RECEIVE DOUBLE
            CASE ELSE: PRINT "IDK"
        END SELECT
    END IF

    CLOSE CLIENT
    _LIMIT 20
LOOP UNTIL UCASE$(INKEY$) = "Q"

SYSTEM 0


Client.bas
Code: (Select All)

_TITLE "Client"
_DEFINE A-Z AS LONG

X = _OPENCLIENT("TCP/IP:5000:localhost")
IF X <> 0 THEN
    D$ = "GSL"
    PUT #X, , D$
    TOSEND = 80
    PRINT TOSEND
    PUT #X, , TOSEND
    _DELAY 1
    CLOSE X
ELSE
    PRINT "error no server"
    _DELAY 1
    SYSTEM 1
END IF

X = _OPENCLIENT("TCP/IP:5000:localhost")
IF X <> 0 THEN
    D$ = "GRL"
    TOSEND = -1
    PUT #X, , D$
    GET #X, , TOSEND
    PRINT TOSEND
    _DELAY 1
    CLOSE X
END IF


apparently the part where I send the data works, but when I receive them in the client, something is wrong.
   

I don't even know if the part where I manipulate the array is well done. I would like to know if you could help me to know what is wrong, I would accept any feedback, thanks.

I don't know if I'm supposed to post this like this


RE: TCP/IP. data from one program to another - bplus - 02-16-2025

@TheLastMan, Abe, what we are all women now?

Ha! Welcome to the forum!

I am, as yet, not interested in TCP/IP but it has been discussed many times here at the forum.
Try a search if you tire waiting for someone to answer.

Your post seems in just the right place to me. Smile

Update: here is quick link to most recent TCP/IP discussion:
https://qb64phoenix.com/forum/showthread.php?tid=3101&pid=28986#pid28986


RE: TCP/IP. data from one program to another - NakedApe - 02-16-2025

Welcome, TheLastMan. Here's another good place to look. Steve's example of program to program hosting.

https://qb64phoenix.com/forum/showthread.php?tid=2858&highlight=%22host%22


RE: TCP/IP. data from one program to another - DSMan195276 - 02-16-2025

The underlying problem is that `GET` does not wait for the data to arrive, if the client has not yet received enough data for your variable then it simply leaves the variable as-is and sets the EOF flag. Because of that, your `PUT` followed by an immediate `GET` of a LONG is very likely to fail because the other program won't have sent its response in time. You can check for this failure by checking `EOF(X)` after the `GET`, if it's set then that indicates the `GET` was unsuccessful.

The simple solution is to just loop until `EOF()` is false, indicating you received the data. You should additionally check `_CONNECTED(X)` in the loop to determine whether the client was disconnected (you don't want to keep looping on `GET` if no data will ever come).

On the `Server.bas` side of things it gets a bit trickier. The `GET`s` in there are unlikely to fail because the messages are currently very short, but you should still be checking `EOF()` and looping to ensure they're successfully received. That approach will be ok at a certain scale but it's not ideal because during the loop the server can't do anything else and you never really know if the client will send the rest of the message. There's a large variety of solutions to this issue, but I'd consider prefixing the messages with a length, that way you can have the main code wait until an entire message is received before you start processing it, then the rest of the code can simply handle the message without having to deal with the connection.


RE: TCP/IP. data from one program to another - TheLastTMan - 02-16-2025

thanks, in other forums they are absurdly delicate with how you address yourself and how you write the post otherwise they almost banned you. i have bad experiences with that, people on the internet become wild very easily.


RE: TCP/IP. data from one program to another - SMcNeill - 02-16-2025

https://qb64phoenix.com/forum/showthread.php?tid=2858 < Try this out and see if it helps.


RE: TCP/IP. data from one program to another - mdijkens - 02-16-2025

I got the same need some time ago and have created this as  a basis:

tcp_server.bas:
Code: (Select All)
$Console:Only
Dim Shared crlf As String * 2: crlf = Chr$(13) + Chr$(10)
Dim Shared hostConn&, conn&(100), conns%

hostConn& = _OpenHost("TCP/IP:1234")
Print _ConnectionAddress$(hostConn&)

Do
  _Limit 10
  newConn& = _OpenConnection(hostConn&)
  If newConn& <> 0 Then
    conns% = conns% + 1: conn&(conns%) = newConn&
    Print "connections:"; conns%
  End If

  If Abs(Timer - tim!) > .1 Then
    out$ = Time$ + " "
    c% = 1
    Do While c% <= conns%
      If _Connected(conn&(c%)) = 0 Then
        Close conn&(c%)
        For i% = c% + 1 To conns%
          conn&(i% - 1) = conn&(i%)
        Next i%
        conns% = conns% - 1
        Print "connections:"; conns%
      Else
        Get #conn&(c%), , in$: If in$ <> "" Then Print c%, in$
        Put #conn&(c%), , out$
      End If
      c% = c% + 1
    Loop
    tim! = Timer
  End If
Loop Until InKey$ <> ""

Close hostConn&
System

tcp_clients.bas:
Code: (Select All)
Do
  _Limit 20

  Do
    m$ = receive$
    If m$ <> "" Then Print m$;
  Loop Until m$ = ""
Loop Until InKey$ = Chr$(27)
Close connect&
System

Function send& (m$)
  c& = connect&
  If c& Then Put #c&, , m$
  send& = c&
End Function

Function receive$
  c& = connect&
  If c& Then Get #c&, , m$
  receive$ = m$
End Function

Function connect&
  Static conn&, hconn&
  If conn& Then If _Connected(conn&) Then connect& = conn&: Exit Function
  If hconn& Then
    conn& = _OpenConnection(hconn&)
  Else
    conn& = _OpenClient("TCP/IP:1234:localhost")
    If Not conn& Then
      hconn& = _OpenHost("TCP/IP:1234")
      If hconn& Then conn& = _OpenConnection(hconn&)
    End If
  End If
  connect& = conn&
End Function

All client messages are sent to all other clients


RE: TCP/IP. data from one program to another - TempodiBasic - 03-04-2025

Hi TheLastMan 
do you have a pizza?
What kind of pizza?

Welcome in QB64pe forum!

I have little experience in TCP/IP because I'm studing it but it seems well supported in QB64pe.

here a seach in the forum 
search for TCP/IP posts

youl'll find the demo of SmcNeill for a banner walking between two windows, other code stuff and some my simple code, both in programs and in games of the section code and stuff.

I found some conceptual bugs into your code... 
  • but as first I must let see you that the Client output is a fake output, you print the client variables just after sent the request of data, no time for the system to process the TCP/IP communication with the server!
  • About code, if you like keywords UPPERCASE it is ok, I find overwelming the use of that you know is useful in OLD QBasic to write a line too long ( peharps more than 255 characters), but this limit is no present in QB64pe!
  • about commands:
             GSL Game Send Long
             GRL Game Received Long
             GSD Game Send Double
             GRF Game Received Double (?? F for what?)

about this stuff:
Code: (Select All)
 Z = UBOUND(SENDEDLONGSG): _
                    if Z <> D then: FOR x = 0 TO Z STEP 1: SWAP SENDEDLONGSG(D), SENDEDLONGSG(x): NEXT: _
                    REDIM _PRESERVE SENDEDLONGSG(Z - 1):  'GAME RECEIVE LONG
it seems to me that your goal is to have a LIFO stack...
  but 
      1. SENDEDLONGSD() starts from 1 not from 0 so the FOR must start from 1
       2. you must assure that z-1 is never <=0 or the index of your array will shift in the negative values during the run of the program.


[Image: Output-TCP-IP-demo.png]


RE: TCP/IP. data from one program to another - TempodiBasic - 03-04-2025

@TheLastMan
here the MOD of your code working... at least about TCP/IP... I haven't fixed bugs of LIFO stack, I have fixed only "error out of range".
Your goal, your will, your code for this issue
I have removed all the underscore for 2 reasons:
  1. they are unuseful
  2. it sometimes stucks the parser giving false errors.
Here the ServerMOD code and ClientMOD code.
Save and run in QB64pe 4.0 or higher.
[Image: immagine-2025-03-04-163722855.png]


RE: TCP/IP. data from one program to another - TempodiBasic - 03-04-2025

@mdijkens
I was trying to get output of your code 
but after copy, paste in the IDE and save it . I got a compiler error both after F5 both after F11.

here compilelog.txt
Quote:"internal\c\c_compiler\bin\mingw32-make.exe" non Š riconosciuto come comando interno o esterno,
un programma eseguibile o un file batch.
it stands also after 
 1.closing and opening again the IDE, 
  2. saving again the file after adding a space character somewhere, 
   3. deleting the TEMP folder in folder QB64pe\internal\
... I have no idea why this happens.

some suggestions?