Mini Messenger - SMcNeill - 05-01-2022
A lot of folks are curious about how we can get our programs to talk to each other, and curious about how we'd use QB64 to communicate via TCP/IP over a network. The wiki has a few examples, but they tend to be outdated and simply don't work for me. (Such as the mini-messenger example in the wiki.) I figured people might like a working example of how to get all the proper parts working together, so I tried various wiki samples and eventually decided to rework one until I got it to working for me...
The finished code here is working as intended on Windows. (I dunno if it'll work for Linux or Mac users, but I'd love to hear if it does or doesn't.) Instead of a single set of code which tries to toggle between client and host, I worked this up as two separate sets of code -- one for each. Copy one set of code into QB64, and then run it. Then, while that program is still running in the background, copy the second set of code and run it.. Type in either program and watch as they happily communicate with each other without any issues.
THE HOST:
Code: (Select All) DIM SHARED Users(1 TO 1000) ' array to hold other client info
DIM SHARED NumClients
DIM SHARED out$
PRINT "[Steve's Mini Messenger]"
host = _OPENHOST("TCP/IP:7319") ' no host found, so begin new host
IF host THEN
PRINT "[Beginning new host chat session!]"
NumClients = 0
client = _OPENCLIENT("TCP/IP:7319:localhost")
IF client = 0 THEN PRINT "ERROR: could not attach host's personal client to host!"
INPUT "Enter your name:", myname$
'PRINT #client, myname$ + " connected!"
PRINT "[Chat session active!]"
ELSE
PRINT "ERROR: Could not begin new host!"
END IF ' host
DO ' host main loop
newclient = _OPENCONNECTION(host) ' receive any new connection
IF newclient THEN
NumClients = NumClients + 1
Users(NumClients) = newclient
PRINT "Welcome to Steve's Mini Messenger!"
END IF
FOR i = 1 TO NumClients
GetMessage Users(i) 'check all clients for a message
IF out$ <> "" THEN
l = LEN(out$)
FOR j = 1 TO NumClients ' distribute incoming messages to all clients
PUT #Users(j), , l
PUT #Users(j), , out$
NEXT
END IF
NEXT i
SendMessage myname$, mymessage$, client
_LIMIT 30
LOOP
SUB GetMessage (client) ' get & display any new message
GET #client, , l
IF l > 0 THEN
out$ = SPACE$(l)
GET #client, , out$
VIEW PRINT 1 TO 20
LOCATE 20, 1
PRINT out$
VIEW PRINT 1 TO 24
ELSE
out$ = ""
END IF
END SUB
SUB SendMessage (myname$, mymessage$, client) ' simple input handler
k$ = INKEY$
IF LEN(k$) THEN
IF k$ = CHR$(8) AND LEN(mymessage$) <> 0 THEN
mymessage$ = LEFT$(mymessage$, LEN(mymessage$) - 1)
ELSE
IF LEN(k$) = 1 AND ASC(k$) >= 32 THEN mymessage$ = mymessage$ + k$
END IF
END IF
VIEW PRINT 1 TO 24
LOCATE 22, 1: PRINT SPACE$(80); ' erase previous message displayed
LOCATE 22, 1: PRINT myname$ + ": "; mymessage$;
IF k$ = CHR$(13) THEN ' [Enter] sends the message
IF mymessage$ = "" THEN SYSTEM ' [Enter] with no message ends program
mymessage$ = myname$ + ":" + mymessage$
l = LEN(mymessage$)
PUT #client, , l
PUT #client, , mymessage$
mymessage$ = ""
END IF
IF k$ = CHR$(27) THEN SYSTEM ' [Esc] key ends program
END SUB
THE CLIENT:
Code: (Select All) DIM SHARED out$
PRINT "[Steve's Mini Messenger]"
client = _OPENCLIENT("TCP/IP:7319:localhost") ' Attempt to connect to local host as a client
PRINT "[connected to " + _CONNECTIONADDRESS(client) + "]"
INPUT "Enter your name: ", myname$
out$ = myname$ + " connected!"
l = LEN(out$)
PUT #client, , l
PUT #client, , out$
DO
GetMessage client
SendMessage myname$, mymessage$, client ' display current input on screen
_LIMIT 30
LOOP
'.................... END OF MAIN PROGRAM ................
SUB GetMessage (client) ' get & display any new message
GET #client, , l
IF l > 0 THEN
out$ = SPACE$(l)
GET #client, , out$
VIEW PRINT 1 TO 20
LOCATE 20, 1
PRINT out$
VIEW PRINT 1 TO 24
ELSE
out$ = ""
END IF
END SUB
SUB SendMessage (myname$, mymessage$, client) ' simple input handler
k$ = INKEY$
IF LEN(k$) THEN
IF k$ = CHR$(8) AND LEN(mymessage$) <> 0 THEN
mymessage$ = LEFT$(mymessage$, LEN(mymessage$) - 1)
ELSE
IF LEN(k$) = 1 AND ASC(k$) >= 32 THEN mymessage$ = mymessage$ + k$
END IF
END IF
VIEW PRINT 1 TO 24
LOCATE 22, 1: PRINT SPACE$(80); ' erase previous message displayed
LOCATE 22, 1: PRINT myname$ + ": "; mymessage$;
IF k$ = CHR$(13) THEN ' [Enter] sends the message
IF mymessage$ = "" THEN SYSTEM ' [Enter] with no message ends program
mymessage$ = myname$ + ":" + mymessage$
l = LEN(mymessage$)
PUT #client, , l
PUT #client, , mymessage$
mymessage$ = ""
END IF
IF k$ = CHR$(27) THEN SYSTEM ' [Esc] key ends program
END SUB
Have fun playing around with this as a local system messenger program. Try it out, kick it around, and let me know if there's anything you don't understand about what it's doing. This isn’t exactly how I'd normally write one of these; but that's because I started with what the wiki had and then gutted it and rebuilt it up until it was actually working for me as it should. Honestly, I think I would've been better off to have just wrote the whole program from scratch!
RE: Mini Messenger - SMcNeill - 05-01-2022
And, here's a version posted by Zeppelin which combines both utilities into one:
Code: (Select All) DIM SHARED Users(1 TO 1000) ' array to hold other client info
DIM SHARED NumClients
DIM SHARED OUT$
PRINT "[Steve's Mini Messenger]"
host = _OPENHOST("TCP/IP:7319") ' no host found, so begin new host
IF host THEN
PRINT "[Beginning new host chat session!]"
NumClients = 0
client = _OPENCLIENT("TCP/IP:7319:localhost")
IF client = 0 THEN PRINT "ERROR: could not attach host's personal client to host!"
INPUT "Enter your name:", myname$
'PRINT #client, myname$ + " connected!"
PRINT "[Chat session active!]"
ELSE
PRINT "ERROR: Could not begin new host!"
PRINT "JOINING as CLIENT"
'Join as client
client = _OPENCLIENT("TCP/IP:7319:localhost") ' Attempt to connect to local host as a client
END IF ' host
IF host THEN
_TITLE "HOST"
DO ' host main loop
newclient = _OPENCONNECTION(host) ' receive any new connection
IF newclient THEN
NumClients = NumClients + 1
Users(NumClients) = newclient
PRINT "Welcome to Steve's Mini Messenger!"
END IF
FOR i = 1 TO NumClients
GetMessage Users(i) 'check all clients for a message
IF OUT$ <> "" THEN
l = LEN(OUT$)
FOR j = 1 TO NumClients ' distribute incoming messages to all clients
PUT #Users(j), , l
PUT #Users(j), , OUT$
NEXT
END IF
NEXT i
SendMessage myname$, mymessage$, client
_LIMIT 30
LOOP
END IF
IF client THEN
INPUT "Enter your name: ", myname$
OUT$ = myname$ + " connected!"
l = LEN(OUT$)
PUT #client, , l
PUT #client, , OUT$
_TITLE "CLIENT"
DO
GetMessage client
SendMessage myname$, mymessage$, client ' display current input on screen
_LIMIT 30
LOOP
END IF
SUB GetMessage (client) ' get & display any new message
GET #client, , l
IF l > 0 THEN
OUT$ = SPACE$(l)
GET #client, , OUT$
VIEW PRINT 1 TO 20
LOCATE 20, 1
PRINT OUT$
VIEW PRINT 1 TO 24
ELSE
OUT$ = ""
END IF
END SUB
SUB SendMessage (myname$, mymessage$, client) ' simple input handler
k$ = INKEY$
IF LEN(k$) THEN
IF k$ = CHR$(8) AND LEN(mymessage$) <> 0 THEN
mymessage$ = LEFT$(mymessage$, LEN(mymessage$) - 1)
ELSE
IF LEN(k$) = 1 AND ASC(k$) >= 32 THEN mymessage$ = mymessage$ + k$
END IF
END IF
VIEW PRINT 1 TO 24
LOCATE 22, 1: PRINT SPACE$(80); ' erase previous message displayed
LOCATE 22, 1: PRINT myname$ + ": "; mymessage$;
IF k$ = CHR$(13) THEN ' [Enter] sends the message
IF mymessage$ = "" THEN SYSTEM ' [Enter] with no message ends program
mymessage$ = myname$ + ":" + mymessage$
l = LEN(mymessage$)
PUT #client, , l
PUT #client, , mymessage$
mymessage$ = ""
END IF
IF k$ = CHR$(27) THEN SYSTEM ' [Esc] key ends program
END SUB
RE: Mini Messenger - Coolman - 05-02-2022
thank you. it's excellent. it would be useful to have a zip package when there are many source codes...
RE: Mini Messenger - James D Jarvis - 05-02-2022
Neato. I was able to add "advanced" features like incoming chat being tabbed over and sending a beep as part of a message in seconds. Fighting the urge to write an eliza chat-bot.
RE: Mini Messenger - RUBIDIUM - 07-05-2022
I've searched for a while now and I can't find something like a messenger to share over the internet and not just local. has that been done on QB64? Was hoping to make something like shared inventory. Can anyone offer any direction?
Thanks,
-R
RE: Mini Messenger - Ikerkaz - 12-08-2022
(05-01-2022, 10:33 PM)SMcNeill Wrote: And, here's a version posted by Zeppelin which combines both utilities into one:
Code: (Select All) DIM SHARED Users(1 TO 1000) ' array to hold other client info
DIM SHARED NumClients
DIM SHARED OUT$
PRINT "[Steve's Mini Messenger]"
host = _OPENHOST("TCP/IP:7319") ' no host found, so begin new host
IF host THEN
PRINT "[Beginning new host chat session!]"
NumClients = 0
client = _OPENCLIENT("TCP/IP:7319:localhost")
IF client = 0 THEN PRINT "ERROR: could not attach host's personal client to host!"
INPUT "Enter your name:", myname$
'PRINT #client, myname$ + " connected!"
PRINT "[Chat session active!]"
ELSE
PRINT "ERROR: Could not begin new host!"
PRINT "JOINING as CLIENT"
'Join as client
client = _OPENCLIENT("TCP/IP:7319:localhost") ' Attempt to connect to local host as a client
END IF ' host
IF host THEN
_TITLE "HOST"
DO ' host main loop
newclient = _OPENCONNECTION(host) ' receive any new connection
IF newclient THEN
NumClients = NumClients + 1
Users(NumClients) = newclient
PRINT "Welcome to Steve's Mini Messenger!"
END IF
FOR i = 1 TO NumClients
GetMessage Users(i) 'check all clients for a message
IF OUT$ <> "" THEN
l = LEN(OUT$)
FOR j = 1 TO NumClients ' distribute incoming messages to all clients
PUT #Users(j), , l
PUT #Users(j), , OUT$
NEXT
END IF
NEXT i
SendMessage myname$, mymessage$, client
_LIMIT 30
LOOP
END IF
IF client THEN
INPUT "Enter your name: ", myname$
OUT$ = myname$ + " connected!"
l = LEN(OUT$)
PUT #client, , l
PUT #client, , OUT$
_TITLE "CLIENT"
DO
GetMessage client
SendMessage myname$, mymessage$, client ' display current input on screen
_LIMIT 30
LOOP
END IF
SUB GetMessage (client) ' get & display any new message
GET #client, , l
IF l > 0 THEN
OUT$ = SPACE$(l)
GET #client, , OUT$
VIEW PRINT 1 TO 20
LOCATE 20, 1
PRINT OUT$
VIEW PRINT 1 TO 24
ELSE
OUT$ = ""
END IF
END SUB
SUB SendMessage (myname$, mymessage$, client) ' simple input handler
k$ = INKEY$
IF LEN(k$) THEN
IF k$ = CHR$(8) AND LEN(mymessage$) <> 0 THEN
mymessage$ = LEFT$(mymessage$, LEN(mymessage$) - 1)
ELSE
IF LEN(k$) = 1 AND ASC(k$) >= 32 THEN mymessage$ = mymessage$ + k$
END IF
END IF
VIEW PRINT 1 TO 24
LOCATE 22, 1: PRINT SPACE$(80); ' erase previous message displayed
LOCATE 22, 1: PRINT myname$ + ": "; mymessage$;
IF k$ = CHR$(13) THEN ' [Enter] sends the message
IF mymessage$ = "" THEN SYSTEM ' [Enter] with no message ends program
mymessage$ = myname$ + ":" + mymessage$
l = LEN(mymessage$)
PUT #client, , l
PUT #client, , mymessage$
mymessage$ = ""
END IF
IF k$ = CHR$(27) THEN SYSTEM ' [Esc] key ends program
END SUB
Hello, I'm trying to run this program on two computers in my own house, but it does not work.
I tried to change the line TCP/IP:7319:localhost and I tried 8080:192.168.1.23 (the host's IP) but it is useless.
What am I doing wrong?
Thank you very much.
RE: Mini Messenger - SMcNeill - 12-08-2022
(12-08-2022, 05:42 PM)Ikerkaz Wrote: Hello, I'm trying to run this program on two computers in my own house, but it does not work.
I tried to change the line TCP/IP:7319:localhost and I tried 8080:192.168.1.23 (the host's IP) but it is useless.
What am I doing wrong?
Thank you very much.
I haven't tried to reproduce what you're doing with 2 computers on the same home network yet, but my first though it that they both need to still use the same ICP/IP port to communicate. Try TCP/IP:7319:localhost and TCP/IP:7319:192.168.1.23, and let me know how that goes for you. (If there's any issues, disable firewall for few minutes on both PCs, if you can, just to rule out that it's not being a cause of problems with you, and then don't forget to re-enable if after testing.)
RE: Mini Messenger - Pete - 12-08-2022
Funny, I typed in Pete for Window 1, and Repete for window 2, but then Re appeared in the first window. It shouldn't do that until the name is entered and the initial message is sent. So, just a small glitch.
You might want to add either a _screenclick or min/restore routine so the windows trade focus. See the Keyword of the day link here:
https://staging.qb64phoenix.com/showthread.php?tid=1238
See my messenger code TCP/IP alternative to the _CLIPBOARD$ keyword in that thread.
I would recommending expanding _SCREENCLICK in that demo to recognize when a window is moved though. Obviously I can't get into that much detail in an explanation demo, but Windows API offers some pretty easy to make ways to tell QB64 where the top-left of your program window is located as well as using _SCREENY and _SCREENX in QB64. With that addition, you won't be blind clicking on your desktop if a window gets moved.
Also, you can use Win32 API to trade focus if you min/restore. That can be partially done with _SCREENICON, too. The WinAPI only example I have at my Messenger app at the QBasic Forum: https://www.tapatalk.com/groups/qbasic/tired-of-talking-to-yourself-all-day-now-you-can-m-t39735.html
Fun stuff, glad you got yours working. If it plays nice with mine we start our own DOScord channel!
Pete
RE: Mini Messenger - Ikerkaz - 12-09-2022
(12-08-2022, 06:10 PM)SMcNeill Wrote: (12-08-2022, 05:42 PM)Ikerkaz Wrote: Hello, I'm trying to run this program on two computers in my own house, but it does not work.
I tried to change the line TCP/IP:7319:localhost and I tried 8080:192.168.1.23 (the host's IP) but it is useless.
What am I doing wrong?
Thank you very much.
I haven't tried to reproduce what you're doing with 2 computers on the same home network yet, but my first though it that they both need to still use the same ICP/IP port to communicate. Try TCP/IP:7319:localhost and TCP/IP:7319:192.168.1.23, and let me know how that goes for you. (If there's any issues, disable firewall for few minutes on both PCs, if you can, just to rule out that it's not being a cause of problems with you, and then don't forget to re-enable if after testing.)
When I open the program both times in the same computer, one is titled "HOST" and the other is titled "CLIENT", but when I open in two different computers both are titled "HOST". I tried what you said changing IPs, but it does not work
EDIT: I changed the code and reprogrammed some parts using TCP/IP:300:192.168.1.23 and now it works !!!!!
|