Main forum > Tutorials

Networking for Cowards - Part 2 - Session detection

<< < (3/4) > >>

FutureCow:
Just a thought. Have a look in the samples you get with GLBasic. I just found there's some networking ones there which might show you how to do whatever networking stuff you're looking for.

bigsofty:
For myself, code only, is a pretty weak substitute for the original text. As it is a new subject to many, a good explanation is required in interpret the accompanying examples.  :(

bigsofty:
Excellent, many thanks for repairing the tutorial!  :good:

codegit:
Thank you  8)

Kitty Hello:
Here's an updated version that uses an extended version on my server. Feel free to directly use the GLBAsic.com server interface for your game, but please tell me before you release it.


--- Code: (glbasic) ---
// --------------------------------- //
// Start: Wednesday, August 27, 2008
// IDE Version: 5.360


// ------------------------------------
// FIND A SESSION ON LAN or INTERNET
// ------------------------------------
// Open firewall ports:
// 27910 TCP - game data transfer - MUST open this one outgoing, and (if you're the server) ingoing
// 27911 UDP - LAN session anouncement, incomming (server)
// 27912 UDP - LAN session anouncement, incomming (client)

// *** HOW TO USE ***
// SessionInit("MyGame", "Chatroom-ID", "UserName", bInternetYesNo%)
// WHILE TRUE
// gPlayer% = SessionKeepAlive(TRUE)   // NETCREATEPLAYER("scribble")
// IF gPlayer<>0 THEN NETSENDMSG(gPlayer%, 0, "Hello World")
// UpdateGame()
// WEND

// *** Internals ***
// The app will try to find a session (chatroom). If a sever exists, it connects.
// If no server exists, it will start a server and ...
// -LAN-mode:      Read from a UDP port for incomming client requests.
// -Internet-mode: Send glbasic.com the IP of this device, registering app name, session-ID.
//                 The client in internet mode will connect to glbasic.com and gain the app-server's IP
//                 and connect to it.

// Set this SUB if you want to get notified on errors
GLOBAL gSessionErrorSUB$    = "" // this SUB is called when an error occours.
GLOBAL gSessionErrorString$ = "" // here you find the error details.




GLOBAL gSessionIsInternet% = FALSE // TRUE: Internet, FALSE: LAN
GLOBAL gSessionIsServer% = FALSE
GLOBAL gSession$ = "INVALID"
GLOBAL gSession_port_nethost% = 27910 // TCP - you must ***open this port***  for incomming connections on your firewall and router, if this computer is the server.
GLOBAL gSession_port_server% = 27911  // UDP - server reads from to this port in LAN network for incomming clients.
GLOBAL gSession_port_client% = 27912  // UDP - client reads from this port in LAN when finding the server.
GLOBAL gSession_net_player% = 0 // NET player id
GLOBAL gSession_net_playername$ = "joe"


// --------------------------------------------
// init the session
// App$     - your app name
// Session$ - the name of the session to find/host (consider that as a chatroom)
// App$+Session$ must be > 10 chars and < 24 chars! Otherwise you get the return value -1 in FindSessionINET$
// port_client - 0:default. UDP port for local LAN broadcasts
// port_server - 0:default. UDP port the server listens to
// --------------------------------------------
FUNCTION SessionInit: App$, Session$, PlayerName$, bIsInternet%, port_nethost%=0, port_client%=0, port_server%=0

STDOUT "session init "+App$+"/"+Session$+"/"+PlayerName$+". Internet: "+bIsInternet%+"\n"

// just to be sure, close connections
SessionKeepAlive(FALSE)

// make unique session string, with safe characters
gSession$ = LEFT$(UCASE$(App$) + "-" + URLENCODE$(UCASE$(Session$)), 24)

gSession_net_playername$ = PlayerName$

gSessionIsInternet% = bIsInternet%

IF port_nethost>0 THEN gSession_port_nethost% = port_nethost%
IF port_client>0  THEN gSession_port_client%  = port_client%
IF port_server>0  THEN gSession_port_server%  = port_server%

// just to be sure
SOCK_INIT()
ENDFUNCTION




// --------------------------------------------
// find a session using a broadcast
// returns "" - still searching
//         IP address - server found
// --------------------------------------------
FUNCTION SessionFindLAN$:
LOCAL sock%, ip$
STDOUT "open udp: "+gSession_port_client%+"\n"

sock% = SOCK_UDPOPEN(gSession_port_client%)
// Uh-oh. Port is still locked
IF sock% <0
SessionError("Can't open UDP port "+gSession_port_client%)
STDOUT NETGETLASTERROR$() + "\n"
STDOUT "can't open udp port (can't connect). Might be still locked from old session\n"
RETURN ""
ENDIF

// find my own IP
ip$ = SOCK_GETIP$(SOCK_GETHOSTIP$(""))
LOCAL ip_broadcast$ = SOCK_GETHOSTIP$("255.255.255.255")

STDOUT "find session\n"
FOR retry% = 1 TO 3
LOCAL rv%, msg$
rv% = SOCK_UDPSEND(sock%, gSession$+"\n"+ip$, ip_broadcast$, gSession_port_server%)
IF rv% = -1
STDOUT NETGETLASTERROR$() + "\n"
STDOUT "SOCK_UDPSEND -1\n"
BREAK
ENDIF

// wait for a response
FOR reread% = 1 TO 5
rv% = SOCK_RECV(sock%, msg$, 128)
IF rv%>0
SOCK_CLOSE(sock%)
STDOUT "server at"+msg$+"\n"
RETURN msg$ // return what the server said
ENDIF

IF rv% = -1
STDOUT "SOCK_RECV -1\n"
GOTO failed
ENDIF

IF rv% = -2 // would block, try again later
STDOUT "."
SLEEP 100
ENDIF
NEXT

// inform about multiple read loops (usually one is enough)
SLEEP 200
NEXT

STDOUT "timed out\n"
@failed:

SOCK_CLOSE(sock%)
RETURN ""
ENDFUNCTION



// --------------------------------------------
// Wait for a client broadcasting a "Where are you" message.
// Then return the current IP address, so the client
// could connect.
// does not return any value
// --------------------------------------------
FUNCTION SessionAnnounceLAN%: bClose%
STATIC sock%
STATIC serverip$

IF bClose%
IF sock% THEN SOCK_CLOSE(sock%)
sock=0
RETURN
ENDIF

IF sock% = 0
serverip$ = SOCK_GETIP$(SOCK_GETHOSTIP$(""))
STDOUT "open udp: "+gSession_port_server%+"\n"
sock% = SOCK_UDPOPEN(gSession_port_server%)
IF sock% <0
STDOUT NETGETLASTERROR$() + "\n"
STDERR "can't host - port locked?\n"
RETURN
ENDIF
ENDIF

// wait for a request
LOCAL rv%, msg$
rv% = SOCK_RECV(sock%, msg$, 512)
IF rv% > 0
STDOUT "incomming LAN broadcast, session: "+msg$+"\n"

// compare session
LOCAL pos% = INSTR(msg$, "\n")
IF pos%>0
IF MID$(msg$, 0, pos%) = gSession$
LOCAL clientip$ = MID$(msg$, pos%+1, -1)
LOCAL clientip_binary$ = SOCK_GETHOSTIP$(clientip$)
// reply
STDOUT "client accepted\n"

// send twice - just to be sure
SOCK_UDPSEND(sock%, serverip$, clientip_binary$, gSession_port_client%)
SLEEP 3
SOCK_UDPSEND(sock%, serverip$, clientip_binary$, gSession_port_client%)
ENDIF
ENDIF
ENDIF

IF rv=-1 // error -> reconnect
SessionError("Can't announce session. Try to reconnect.")
STDOUT "announce_session - error. Try reconnect\n"
SOCK_CLOSE(sock%)
sock% = 0
ENDIF
ENDFUNCTION


FUNCTION SessionFindINET$:
LOCAL ip$
// see if there is already a session
ip$ = NETWEBGET$("www.glbasic.com", "/netsession.php?session="+gSession$+"&host=0", 0, 256)

STDOUT "Find internet session: "+ip$+"\n"

IF LEN(ip$)>4 THEN RETURN ip$
RETURN ""
ENDFUNCTION


// Announce session in INET
// true/false
FUNCTION SessionAnnounceINET%: bClose%
LOCAL ip$
STATIC bIsOpen%=FALSE
STATIC time_next_annc = 0 // don't connect to internet on every function call

IF bClose% = FALSE
bIsOpen% = FALSE

LOCAL now =GETTIMERALL()
IF now>time_next_annc
ip$ = NETWEBGET$("www.glbasic.com", "/netsession.php?session="+gSession$+"&host=1", 0, 256)
STDOUT "internet hosting game: "+ip$+"\n"
IF ip$="HOSTED"
bIsOpen% = TRUE
time_next_annc = GETTIMERALL() + 5 * 60 * 1000
ELSE
SessionError("Can't announce in internet.")
STDOUT NETGETLASTERROR$() + "\n"
ENDIF
ENDIF

RETURN bIsOpen%
ELSE
// tell the server to stop it
IF bIsOpen%
ip$=NETWEBGET$("www.glbasic.com", "/netsession.php?session="+gSession$+"&host=-1", 0, 256)
STDOUT "Stopped hosting internet game: "+ip$+"\n"
ENDIF
bIsOpen% = FALSE
time_next_annc = 0
RETURN TRUE
ENDIF
ENDFUNCTION




// just call this function every now and then to get going
// this returns your player-ID for NETSEND and such...
FUNCTION SessionKeepAlive%: bKeepAlive%
STATIC bConnected% = FALSE
IF NOT bKeepAlive // Shutdown
STDOUT "Session shutdown\n"
IF gSessionIsInternet
SessionAnnounceINET(TRUE)
ELSE
SessionAnnounceLAN(TRUE)
ENDIF
bConnected = FALSE
NETSHUTDOWN
SOCK_SHUTDOWN
gSession_net_player = 0
gSessionIsServer% = FALSE
RETURN
ENDIF


IF NOT bConnected% // join session
gSessionIsServer% = FALSE
gSession_net_player%=0
LOCAL ip$
IF gSessionIsInternet
ip$ = SessionFindINET$()
ELSE
ip$ = SessionFindLAN$()
ENDIF

IF LEN(ip$)>4
STDOUT "found sesstion. Try to NETJOINGAME "+ip$+":"+gSession_port_nethost%+"...\n"
IF NETJOINGAME(ip$, gSession_port_nethost%)
STDOUT "...OK\n"
bConnected% = TRUE

// STDOUT "Number of players: "+NETNUMPLAYERS() + "\n"
ELSE
SessionError("Failed to join game session at "+ip$+":"+gSession_port_nethost%)
STDOUT NETGETLASTERROR$() + "\n"
ENDIF
ENDIF
ENDIF

IF NOT bConnected%
STDOUT "Trying to host a session...\n"
gSession_net_player%=0
bConnected% = NETHOSTGAME(gSession_port_nethost%)
IF bConnected%
NETALLOWJOINING TRUE
gSessionIsServer% = TRUE

// See if we can be reached from the internet
IF gSessionIsInternet
LOCAL isok$ = NETWEBGET$("www.glbasic.com", "/netsession.php?ping="+gSession_port_nethost%, 0, 256)
IF LEFT$(isok$, 2) <> "OK"
SessionError("FIREWALL blocked port "+gSession_port_nethost%)
STDOUT isok$+"\n"
ELSE
STDOUT "Firewall post "+gSession_port_nethost%+" is open. Clients can connect.\n"
ENDIF
ENDIF
ENDIF
ENDIF


IF bConnected% // announce session
IF gSessionIsInternet
SessionAnnounceINET(FALSE)
ELSE
SessionAnnounceLAN(FALSE)
ENDIF

IF NOT NETISACTIVE()
gSession_net_player%=0
bConnected=FALSE
ENDIF
ENDIF

// no player created
IF bConnected% AND gSession_net_player% = 0
gSession_net_player% = NETCREATEPLAYER(gSession_net_playername$)
STDOUT "created player"+gSession_net_player%+"\n"
ENDIF


RETURN gSession_net_player%

ENDFUNCTION



FUNCTION SessionError%: err$
STDOUT "ERROR: "+err$+"\n"
gSessionErrorString$ = err$
CALLBYNAME( gSessionErrorSUB$)
ENDFUNCTION


--- End code ---

Navigation

[0] Message Index

[#] Next page

[*] Previous page

Go to full version