Client/server
Blitz3D Forums/Blitz3D Beginners Area/Client/server
| ||
| Hello, I remember someone had tried successfully to make a client/server architecture (using TCP/IP) with Blitz (as client) and PureBasic as server. I wrote a very initial implementation, but I got some problems I can't resolve. If I run the two programs on ONE computer, it works. Between two computers, the connection is estabilished, but it seems the client sends TWO data packets, instead of one. Here it is the two sources. I hope you don't mind if one is written in PureBasic.
Const MB_OK= 0
Const MB_ICONERROR= 16
; --- TIPI DI MESSAGGIO
Const MSG_NEW= 170
Const MSG_LIST= 240
Const MSG_LOGIN= 255
Const MSG_EVENT= 85
Const MSG_END= 226
; --- TIPI DI EVENTO
Const START= 24
Const ACCEPT= 129
Const MOVE= 204
Const ANSWER= 51
Const CHAT= 231
Const GAMEOVER= 7
; --- CLASSE PLAYER
Type Player
Field Name$
Field IP%
Field Enemy_IP%
Field FlagFirst ; 1= ha richiesto la partita per primo
Field TotalWon
Field TotalLost
End Type
BUFFER_connessione=CreateBank(1024)
Dim Utenti$(255)
Port=6832
Server_IP$="192.168.1.3"
Nome_Utente$=Input("User Name: ")
; si connette al server
HANDLE_tcp=OpenTCPStream(Server_IP$,Port)
If Not HANDLE_tcp
MessageBox(0,"Impossibile stabilire una connessione con il server TW.","TWClient",MB_OK Or MB_ICONERROR)
End
EndIf
DebugLog "Connesso."
; attende l'arrivo del pacchetto MSG_NEW
ReadBytes(BUFFER_connessione,HANDLE_tcp,0,6)
DebugLog PeekByte(BUFFER_connessione,0)
DebugLog PeekInt(BUFFER_connessione,1)
DebugLog PeekByte(BUFFER_connessione,5)
Print PeekByte(BUFFER_connessione,0)
Print PeekInt(BUFFER_connessione,1)
Print PeekByte(BUFFER_connessione,5)
c=PeekInt(BUFFER_connessione,1)
; attende l'arrivo del pacchetto MSG_LIST
If c>1
ReadBytes(BUFFER_connessione,HANDLE_tcp,0,c)
l=0
For i=1 To c
t=PeekByte(BUFFER_connessione,i)
If t=35
l=l+1
Else
Utenti$(l)=Utenti$(l)+Chr$(t)
EndIf
DebugLog PeekByte(BUFFER_connessione,i)
Next
Print Utenti$(0)
Print Utenti$(1)
Print Utenti$(2)
Print Utenti$(3)
Print Utenti$(4)
Print Utenti$(5)
Print Utenti$(6)
Print Utenti$(7)
Print Utenti$(8)
Print Utenti$(9)
Print Utenti$(10)
Print Utenti$(11)
EndIf
; invia il pacchetto MSG_LOGIN
DebugLog "MSG_LOGIN ..."
;tmp$=Chr(MSG_LOGIN)+Nome_Utente$+Chr(MSG_END)
;WriteString(HANDLE_tcp,tmp$)
WriteString(HANDLE_tcp,Chr(MSG_LOGIN)+Nome_Utente$+Chr(MSG_END))
Print "Batti INVIO per uscire."
e$=Input()
CloseTCPStream(HANDLE_tcp)
End
; --- TIPI DI MESSAGGIO
#MSG_HELLO= 170
#MSG_LIST= 240
#MSG_LOGIN= -1
#MSG_EVENT= 85
#MSG_END= -30
; --- TIPI DI EVENTO
#START= 24
#ACCEPT= 129
#MOVE= 204
#ANSWER= 51
#CHAT= 231
#GAMEOVER= 7
; --- CLASSE PLAYER
Structure Player
Name.s
ID.l
IP.l
Enemy_ID.l
Enemy_IP.l
FlagFirst.b ; 1= ha richiesto la partita per primo
TotalWon.l
TotalLost.l
EndStructure
OpenConsole()
InitNetwork()
ExamineIPAddresses()
res=NextIPAddress()
Server_IP.s=IPString(res)
tmp$=UCase(ProgramParameter())
If tmp$="/P" Or tmp$="/PORT"
tmp$=ProgramParameter()
Port=Val(tmp$)
Else
; Port=6933
Port=6832
EndIf
If CreateNetworkServer(0,Port)
NewList PlayerList.Player()
*BUFFER_connessioni=AllocateMemory(1024)
OpenWindow(0,0,0,320,240,"Total War Server "+Str(Port),#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
Repeat
WEvent=WindowEvent()
If WEvent=#PB_Event_CloseWindow
Quit=1
EndIf
SERVER_event=NetworkServerEvent()
If SERVER_event
Debug "evento server"
ID_client.l=EventClient()
Select SERVER_event
Case 1
Debug "nuova connessione di un client "
; ricava la lista dei giocatori connessi
tmp$=""
ResetList(PlayerList())
While NextElement(PlayerList())
tmp$+PlayerList()\Name+"#"
Wend
c=Len(tmp$)+1
; invio del pacchetto MSG_HELLO
Debug "MSG_HELLO"
PokeB(*BUFFER_connessioni,#MSG_HELLO)
PokeL(*BUFFER_connessioni+1,c)
PokeB(*BUFFER_connessioni+5,#MSG_END)
SendNetworkData(ID_client,*BUFFER_connessioni,6)
If c>1
; invio del pacchetto MSG_LIST
Debug "MSG_LIST"
PokeB(*BUFFER_connessioni,#MSG_LIST)
PokeS(*BUFFER_connessioni+1,tmp$)
PokeB(*BUFFER_connessioni+c,#MSG_END)
SendNetworkData(ID_client,*BUFFER_connessioni,c)
EndIf
Case 4
Debug "chiusa una connessione"
Default
Debug "arrivati dati"
PrintN("arrivati dati")
RequestLength.l=ReceiveNetworkData(ID_client,*BUFFER_connessioni,512)
Debug "LENGTH= "+Str(RequestLength)
PrintN("LENGTH= "+Str(RequestLength))
For a=0 To RequestLength-1
Debug PeekB(*BUFFER_connessioni+a)
PrintN(Str(PeekB(*BUFFER_connessioni+a)))
Next
Select PeekB(*BUFFER_connessioni+4)
Case #MSG_LOGIN
Debug "MSG_LOGIN"
PrintN("MSG_LOGIN")
c=PeekL(*BUFFER_connessioni)-2
tmp$=PeekS(*BUFFER_connessioni+5,c)
Debug tmp$
PrintN(tmp$)
Debug ID_client
PrintN(Str(ID_client))
IP=GetClientIP(ID_client)
Debug IPString(IP)
PrintN(IPString(IP))
; aggiunge un nuovo giocatore alla lista
AddElement(PlayerList())
PlayerList()\Name=tmp$
PlayerList()\ID=ID_client
PlayerList()\IP=IP
Case #MSG_EVENT
Debug "MSG_EVENT"
EndSelect
; Gosub ProcessRequest
EndSelect
Else
Sleep_(20)
EndIf
Until Quit=1
CloseNetworkServer(0)
Else
MessageBox_(0,"Non è possibile creare il server.","TWServer",#MB_OK|#MB_ICONERROR)
EndIf
End
Basically it works like this: when the server gets a new connection from a client, it sends a MSG_HELLO packet that contains the LENGTH (as LONG) of the further MSG_LIST to be sent, that is a list of all connected user names. In this way the Blitz client waits for the right size of the MSG_LIST packet. Then the client sends a MSG_LOGIN packet with a new user name to be added. As said, it works when both server and client are on the same computer. I tried on two different computers of my home network, but it doesn't work properly. It seems the server receives two MSG_LOGIN packets. Here it is a sample of the output of the PB server program : data arrived LENGTH=4 7 0 0 0 data arrived LENGTH=7 -1 65 66 67 68 69 -30 The bytes are correct, but I don't understand why it gets two packets. When you do: WriteString(HANDLE_tcp,Chr(MSG_LOGIN)+Nome_Utente$+Chr(MSG_END)) Each Blitz string is stored in the file as a 4 byte integer followed by the characters that form the string. Actually if you look above, 7 is the length of the string. But I can't understand why I get two packets. If I try in local (127.0.0.1), I only get one packet like this: data arrived LENGTH=11 7 0 0 0 -1 65 66 67 68 69 -30 May you give me some suggestions ? Thank you VERY MUCH in advance. |
| ||
| suggestion: have you tried using writeline instead of writestring? |
| ||
| Thanks for reply. Actually I tried with WriteBytes() and it gets all bytes in ONE packet. I'll try WriteLine() too just for curiosity. WriteString() is useful because it adds the length and it's handy (I could it manually though). I could even live with two packets, but I should be sure it always sends two packets... in local it sends only one packet. |