[RESOLU] Problème connexion client/serveur

Vous débutez et vous avez besoin d'aide ? N'hésitez pas à poser vos questions
deeph
Messages : 33
Inscription : lun. 20/juil./2009 11:04
Contact :

[RESOLU] Problème connexion client/serveur

Message par deeph »

Bonjour,

Ça fait pas mal de temps maintenant que je bosse sur mon moteur d'MMORPG 2D, mais là je suis confronté à un problème que je n'arrive pas à résoudre.

Mon serveur accepte la connexion d'un client, puis au 2nd il me renvoi un "Invalid Memory Access." :

Code : Tout sélectionner

Procedure ReceiveEncodedData(ClientID.l)
  ResetList(t_client())
  While NextElement(t_client())
    If t_client()\id  = ClientID
      If ReceiveNetworkData(ClientID, t_client()\buffer, 1000)
        Base64Decoder(t_client()\buffer, MemorySize(t_client()\buffer), t_client()\buffer, MemorySize(t_client()\buffer))
      EndIf
      Break
    EndIf
  Wend

  If ListSize(t_client()) > 0
    If t_client()\buffer <> #Null
      Select PeekL(t_client()\buffer)
        Case #CLIENT_verif
          AddElement(client())
          client()\id = t_client()\id
          Define message.s = PeekS(t_client()\buffer+4)
          client()\login = Left(message, FindString(message, Chr(221), 1)-1)
          client()\pass = Right(message, Len(message)-FindString(message, Chr(221), 1))
          client()\ip = t_client()\ip
          client()\timer = ElapsedMilliseconds() + 600000
          ; /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\
          client()\buffer = AllocateMemory(1000) ; /!\ Ici ça foire /!\
          ; /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\
          PrintN(FormatDate("%hh:%ii | ", Date())+"Login : "+client()\login)
          PrintN(FormatDate("%hh:%ii | ", Date())+"Mot de passe : "+client()\pass)
          If DatabaseQuery(#DataBase, "SELECT * FROM player WHERE login = '"+client()\login+"' AND pass = '"+MD5Fingerprint(@client()\pass, Len(client()\pass))+"'")
            If NextDatabaseRow(#DataBase)
              PrintN(FormatDate("%hh:%ii | ", Date())+"Identification valid"+Chr(130)+"e")
              ;envoyer confirmation
              FreeMemory(t_client()\buffer)
              DeleteElement(t_client())
            Else
              PrintN(FormatDate("%hh:%ii | ", Date())+"Identification refus"+Chr(130)+"e")
              SendEncodedMessageToT_Client(t_client()\id, #SERVER_refus, "")
              FreeMemory(client()\buffer)
              DeleteElement(client())
            EndIf
            FinishDatabaseQuery(#DataBase)
          Else
            PrintN(FormatDate("%hh:%ii | ", Date())+"Identification refus"+Chr(130)+"e")
            SendEncodedMessageToT_Client(t_client()\id, #SERVER_refus, "")
            FreeMemory(client()\buffer)
            DeleteElement(client())
          EndIf
      EndSelect
    EndIf
  EndIf

  ResetList(client())
  While NextElement(client())
    If client()\id  = ClientID
      client()\timer = ElapsedMilliseconds() + 600000
      If ReceiveNetworkData(ClientID, client()\buffer, 1000)
        Base64Decoder(client()\buffer, MemorySize(client()\buffer), client()\buffer, MemorySize(client()\buffer))
      EndIf
      Break
    EndIf
  Wend

  If ListSize(client()) > 0
    If client()\Buffer <> #Null
      
    EndIf
  EndIf
EndProcedure
Ce serait peut être dû à l'utilisation de structures mais dans ce cas là je vois pas comment régler le problème...
Dernière modification par deeph le mar. 13/avr./2010 8:40, modifié 1 fois.
Cls
Messages : 620
Inscription : mer. 22/juin/2005 8:51
Localisation : Nantes

Re: Problème connexion client/serveur

Message par Cls »

Je te conseille d'utiliser les Map pour la gestion des clients sur un serveur. Du coup au lieu de faire une recherche avec un While:Wend, tu utilises l'idClient pour accéder directement aux infos de tes clients (Map est apparu en 4.40 il me semble).

D'autre part, tu utilises deux listes chainées client() et t_client(). Je suppose que t_client stocke les clients connectés au serveur et client(), les clients authentifiés. Je te conseille de réunir ces 2 listes dans une seul Map. Ce sera beaucoup plus simple à gérer.

Troisième chose, tu n'as pas besoin de créer autant de buffer de réception qu'il y a des clients. Assure toi cependant de bien boucler sur le buffer de récéption. Actuellement si tes clients envoi plus de 1000 octets, seul les 1000 premiers octets sont traités... Et les autres sont garder en file d'attente. Il faut faire un while : wend sur la fonction ReceiveNetworkData() pour corriger ça.

Voilà, je ne peux pas tester actuellement car je n'ai pas PB sous la main mais ce serait bien de mettre un code qui marche direct pour tester ;)

Voilou bon courage !
deeph
Messages : 33
Inscription : lun. 20/juil./2009 11:04
Contact :

Re: Problème connexion client/serveur

Message par deeph »

Ok je vais me renseigner pour les maps :)

Y'a le code source en entier dans le lien que j'ai posté plus haut si tu veux tester.
Cls a écrit :D'autre part, tu utilises deux listes chainées client() et t_client(). Je suppose que t_client stocke les clients connectés au serveur et client(), les clients authentifiés. Je te conseille de réunir ces 2 listes dans une seul Map. Ce sera beaucoup plus simple à gérer.
Oui, t_client c'est pour les clients temporaires. Dans la suite du code (notamment "main.pb" du serveur), c'est beaucoup plus optimisé avec deux listes je trouve.
Cls a écrit :Troisième chose, tu n'as pas besoin de créer autant de buffer de réception qu'il y a des clients. Assure toi cependant de bien boucler sur le buffer de récéption. Actuellement si tes clients envoi plus de 1000 octets, seul les 1000 premiers octets sont traités... Et les autres sont garder en file d'attente. Il faut faire un while : wend sur la fonction ReceiveNetworkData() pour corriger ça.
Je sais pas trop, avoir autant de buffer que de client me permet de stocker les infos puis ensuite de les traiter, sinon je pense qu'il y en a beaucoup qui vont disparaitre (mais j'me goure peut être)...

Merci !
G-Rom
Messages : 3641
Inscription : dim. 10/janv./2010 5:29

Re: Problème connexion client/serveur

Message par G-Rom »

c'est beaucoup plus optimisé avec deux listes je trouve.
Bonjour , non , ce n'est pas "optimisé". pour cela il faut utilisé une simple structure avec un boolean ou autres type de flag

Code : Tout sélectionner

structure CLIENTS
 Pseudo.s
 IP.s
 Status.i  // <- Tu colles une constante pour connaitre le statut du client ( #IS_JUST_ARRIVE / #IS_WAITING / etc... )
endstructure
deeph
Messages : 33
Inscription : lun. 20/juil./2009 11:04
Contact :

Re: Problème connexion client/serveur

Message par deeph »

Je compte rajouter des trucs dans la structure des clients connectés (en rapport avec le mmorpg), et puis c'est plus simple pour gérer le timeout et la déconnexion de clients temporaires.
Cls
Messages : 620
Inscription : mer. 22/juin/2005 8:51
Localisation : Nantes

Re: Problème connexion client/serveur

Message par Cls »

deeph a écrit :Je sais pas trop, avoir autant de buffer que de client me permet de stocker les infos puis ensuite de les traiter, sinon je pense qu'il y en a beaucoup qui vont disparaitre (mais j'me goure peut être)...
Ce qu'il faut savoir c'est que tout ce qui arrive via un ReceiveNetworkData() est mis en file d'attente. En gros si tu ne traites qu'une partie des données (genre 1000 octets), le reste ne disparaitra pas mais sera traité à la prochaine itération (à ton prochain ReceiveNetworkData() en fait).

Il faut toujours faire une boucle sur le ReceiveNetworkData() (voir la doc pour définir le test d'arrêt). Imagine qu'un client mal intentionné envoi 3000 octets. Sans boucle, tu ne traites simultanément que 1000 octets de manière correcte et les 2000 restants sont traités en 2 fois comme étant 2 requêtes distinctes. Si ton programme est mal conçu dans le traitement des paquets de données, c'est le plantage assuré (j'en ai fait plusieurs fois la fâcheuse expérience :().

Pour le reste, tu fais comme tu veux, chacun a ses propres techniques et ce ne certainement pas moi qui doit te dire comment programmer ! ;)

Je testerai ton programme quand j'aurais PB sous la main.
deeph
Messages : 33
Inscription : lun. 20/juil./2009 11:04
Contact :

Re: [RESOLU] Problème connexion client/serveur

Message par deeph »

Ça y est ça marche 8)

Juste au cas où ça puisse servir à quelqu'un :

Serveur :

Code : Tout sélectionner

EnableExplicit
#VERSION = "0.1"
#RECEIVEBUFFERSIZE = 10000
#SENDBUFFERSIZE = 10000

Enumeration 42
  #SERVER_verif
  #SERVER_valid
  #SERVER_refus
  #SERVER_welcome
  #SERVER_disconnect
  #CLIENT_verif
  #CLIENT_speak
  #CLIENT_list
EndEnumeration

Structure t_client
  id.l
  ip.l
  timer.l
EndStructure

Global NewList t_client.t_client()

Structure client
  id.l
  login.s
  pass.s
  ip.l
  timer.l
EndStructure

Global NewList client.client()
Global *receive_buffer.l = AllocateMemory(#RECEIVEBUFFERSIZE)
Global *receive_buffer_e.l = AllocateMemory(1.4*#RECEIVEBUFFERSIZE)
Global *send_buffer.l = AllocateMemory(#SENDBUFFERSIZE)
Global *send_buffer_e.l = AllocateMemory(1.4*#SENDBUFFERSIZE)

Declare Main()
Declare Frame(message.s)
Declare CheckDatabaseUpdate(Database.l, Query.s)

Enumeration
  #Server
  #DataBase
EndEnumeration

Declare Init()

Procedure Init()
  If InitNetwork()=0
    MessageRequester("Erreur InitNetwork()", "Impossible d'initialiser le reseau.",0)
    End
  EndIf

  If OpenConsole() = 0
    MessageRequester("Erreur OpenConsole()", "Impossible d'ouvrir la console.")
    End
  EndIf

  ConsoleTitle ("Serveur MMORPG v"+#VERSION)

  UseSQLiteDatabase()

  Define i.l

  Global str.s
  For i = 1 To 80
    str = str + Chr(205)
  Next
EndProcedure

Declare SendEncodedMessageToClient(ClientID.l, type.l, message.s)
Declare SendEncodedMessageToT_Client(ClientID.l, type.l, message.s)
Declare ReceiveEncodedData(ClientID.l)

Procedure SendEncodedMessageToClient(ClientID.l, type.l, message.s)
  PokeL(*send_buffer, type)
  If message <> ""
    PokeS(*send_buffer+4, message)
  EndIf
  Base64Encoder(*send_buffer, #SENDBUFFERSIZE, *send_buffer_e, 1.4*#SENDBUFFERSIZE)
  ResetList(client())
  While NextElement(client())
    If client()\id = ClientID
      SendNetworkData(client()\id, *send_buffer_e, 1.4*#SENDBUFFERSIZE)
    EndIf
  Wend
  FillMemory(*send_buffer, #SENDBUFFERSIZE)
  FillMemory(*send_buffer_e, 1.4*#SENDBUFFERSIZE)
EndProcedure

Procedure SendEncodedMessageToT_Client(ClientID.l, type.l, message.s)
  PokeL(*send_buffer, type)
  If message <> ""
    PokeS(*send_buffer+4, message)
  EndIf
  Base64Encoder(*send_buffer, #SENDBUFFERSIZE, *send_buffer_e, 1.4*#SENDBUFFERSIZE)
  ResetList(t_client())
  While NextElement(t_client())
    If t_client()\id = ClientID
      SendNetworkData(t_client()\id, *send_buffer_e, 1.4*#SENDBUFFERSIZE)
    EndIf
  Wend
  FillMemory(*send_buffer, #SENDBUFFERSIZE)
  FillMemory(*send_buffer_e, 1.4*#SENDBUFFERSIZE)
EndProcedure

Procedure ReceiveEncodedData(ClientID.l)
  Protected result.l = 0, message.s

  ResetList(t_client())
  While NextElement(t_client())
    If t_client()\id  = ClientID
      Repeat
        result = ReceiveNetworkData(t_client()\id, *receive_buffer_e, 1.4*#RECEIVEBUFFERSIZE)
      Until result = 1.4*#RECEIVEBUFFERSIZE
      Base64Decoder(*receive_buffer_e, 1.4*#RECEIVEBUFFERSIZE, *receive_buffer, #RECEIVEBUFFERSIZE)
      Select PeekL(*receive_buffer)
        Case #CLIENT_verif
          AddElement(client())
          client()\id = t_client()\id
          message = PeekS(*receive_buffer+4)
          client()\login = Left(message, FindString(message, Chr(221), 1)-1)
          client()\pass = Right(message, Len(message)-FindString(message, Chr(221), 1))
          client()\ip = t_client()\ip
          client()\timer = ElapsedMilliseconds() + 600000
          PrintN(FormatDate("%hh:%ii | ", Date())+"Login : "+client()\login)
          PrintN(FormatDate("%hh:%ii | ", Date())+"Mot de passe : "+client()\pass)
          If DatabaseQuery(#DataBase, "SELECT * FROM player WHERE login = '"+client()\login+"' AND pass = '"+MD5Fingerprint(@client()\pass, Len(client()\pass))+"'")
            If NextDatabaseRow(#DataBase)
              PrintN(FormatDate("%hh:%ii | ", Date())+"Identification valid"+Chr(130)+"e")
              ;envoyer confirmation
              DeleteElement(t_client(), 1)
            Else
              PrintN(FormatDate("%hh:%ii | ", Date())+"Identification refus"+Chr(130)+"e")
              SendEncodedMessageToT_Client(t_client()\id, #SERVER_refus, "")
              DeleteElement(client(), 1)
            EndIf
            FinishDatabaseQuery(#DataBase)
          Else
            PrintN(FormatDate("%hh:%ii | ", Date())+"Identification refus"+Chr(130)+"e")
            SendEncodedMessageToT_Client(t_client()\id, #SERVER_refus, "")
            DeleteElement(client(), 1)
          EndIf
        EndSelect
      FillMemory(*receive_buffer, #RECEIVEBUFFERSIZE)
      FillMemory(*receive_buffer_e, 1.4*#RECEIVEBUFFERSIZE)
      ProcedureReturn
    EndIf
  Wend

  ResetList(client())
  While NextElement(client())
    If client()\id  = ClientID
      client()\timer = ElapsedMilliseconds() + 600000
      Repeat
        result = ReceiveNetworkData(client()\id, *receive_buffer_e, 1.4*#RECEIVEBUFFERSIZE)
      Until result = 1.4*#RECEIVEBUFFERSIZE
      Base64Decoder(*receive_buffer_e, 1.4*#RECEIVEBUFFERSIZE, *receive_buffer, #RECEIVEBUFFERSIZE)
      ; etc...
      FillMemory(*receive_buffer, #RECEIVEBUFFERSIZE)
      FillMemory(*receive_buffer_e, 1.4*#RECEIVEBUFFERSIZE)
      Break
    EndIf
  Wend
EndProcedure

Init()
Main()
End

Procedure Main()
  If *receive_buffer = 0 Or *receive_buffer_e = 0 Or *send_buffer = 0 Or *send_buffer_e = 0
    MessageRequester("Erreur AllocateMemory()", "Impossible d'allouer la mémoire nécessaire.",0)
    End
  EndIf
  ExamineIPAddresses()
  Global Ip.l = NextIPAddress(), Port.l
  Frame("Serveur MMORPG v"+#VERSION+" - deeph")
  PrintN("")
  Repeat
    Print("Port : ")
    Port = Val(Input())
    PrintN("")
  Until Port > 0 And Port < 65000
  If CreateNetworkServer(#Server, Port)
    PrintN(FormatDate("%hh:%ii | ", Date())+"Serveur "+IPString(Ip)+":"+Str(Port)+" lanc"+Chr(130))
    If OpenDatabase(#DataBase, "mmorpg.sqlite", "", "")
      PrintN(FormatDate("%hh:%ii | ", Date())+"Base de donn"+Chr(130)+"e ouverte")
    Else
      PrintN(FormatDate("%hh:%ii | ", Date())+"Impossible d'ouvrir la base de donn"+Chr(130)+"e : "+DatabaseError())
      End
    EndIf
  Else
    PrintN(FormatDate("%hh:%ii | ", Date())+"Impossible de lancer le serveur")
    End
  EndIf

  Repeat
    Select NetworkServerEvent()
      Case #PB_NetworkEvent_Connect
        AddElement(t_client())
        t_client()\id = EventClient()
        t_client()\ip = GetClientIP(t_client()\id)
        t_client()\timer = ElapsedMilliseconds() + 10000
        PrintN(FormatDate("%hh:%ii | ", Date())+"Tentative de connexion au serveur")
        SendEncodedMessageToT_Client(t_client()\id, #SERVER_verif, "")
      Case #PB_NetworkEvent_Data
        ReceiveEncodedData(EventClient())
      Case #PB_NetworkEvent_Disconnect
        ForEach client()
          If client()\id  = EventClient()
            DeleteElement(client(), 1)
            Break
          EndIf
        Next
    EndSelect
    ForEach t_client()
      If t_client()\timer < ElapsedMilliseconds()
        PrintN(FormatDate("%hh:%ii | ", Date())+"Timeout du client temporaire n"+Chr(176)+Str(t_client()\id))
        DeleteElement(t_client(), 1)
      EndIf
    Next
    Delay(5)
  ForEver
EndProcedure

Procedure Frame(message.s)
  PrintN(Chr(201)+Left(str, Len(message)+2)+Chr(187))
  PrintN(Chr(186)+" "+message+" "+Chr(186))
  PrintN(Chr(200)+Left(str, Len(message)+2)+Chr(188))
EndProcedure

Procedure CheckDatabaseUpdate(Database.l, Query.s)
  Define result.l = DatabaseUpdate(Database, Query)
  If result = 0
    PrintN(DatabaseError())
  EndIf
  ProcedureReturn result
EndProcedure
Client :

Code : Tout sélectionner

EnableExplicit
#VERSION = "0.1"
#RECEIVEBUFFERSIZE = 10000
#SENDBUFFERSIZE = 10000

Enumeration 42
  #SERVER_verif
  #SERVER_valid
  #SERVER_refus
  #SERVER_welcome
  #SERVER_disconnect
  #CLIENT_verif
  #CLIENT_speak
  #CLIENT_list
EndEnumeration

Global *receive_buffer.l = AllocateMemory(#RECEIVEBUFFERSIZE)
Global *receive_buffer_e.l = AllocateMemory(1.4*#RECEIVEBUFFERSIZE)
Global *send_buffer.l = AllocateMemory(#SENDBUFFERSIZE)
Global *send_buffer_e.l = AllocateMemory(1.4*#SENDBUFFERSIZE)

Declare Main()
Declare Frame(message.s)

Declare Init()

Procedure Init()
  If InitNetwork()=0
    MessageRequester("Erreur InitNetwork()", "Impossible d'initialiser le reseau.",0)
    End
  EndIf

  If OpenConsole() = 0
    MessageRequester("Erreur OpenConsole()", "Impossible d'ouvrir la console.")
    End
  EndIf

  ConsoleTitle ("Client MMORPG v"+#VERSION)

  Define i.l

  Global str.s
  For i = 1 To 80
    str = str + Chr(205)
  Next
EndProcedure

Declare SendEncodedMessageToServer(Connexion.l, type.l, message.s)
Declare ReceiveEncodedData(Connexion.l)

Procedure SendEncodedMessageToServer(Connexion.l, type.l, message.s)
  PokeL(*send_buffer, type)
  If message <> ""
    PokeS(*send_buffer+4, message)
  EndIf
  Base64Encoder(*send_buffer, #SENDBUFFERSIZE, *send_buffer_e, 1.4*#SENDBUFFERSIZE)
  SendNetworkData(Connexion, *send_buffer_e, 1.4*#SENDBUFFERSIZE)
  FillMemory(*send_buffer, #SENDBUFFERSIZE)
  FillMemory(*send_buffer_e, 1.4*#SENDBUFFERSIZE)
EndProcedure

Procedure ReceiveEncodedData(Connexion.l)
  Protected result.l, login.s, pass.s
  Repeat
    result = ReceiveNetworkData(Connexion, *receive_buffer_e, 1.4*#RECEIVEBUFFERSIZE)
  Until result = 1.4*#RECEIVEBUFFERSIZE
  Base64Decoder(*receive_buffer_e, 1.4*#RECEIVEBUFFERSIZE, *receive_buffer, #RECEIVEBUFFERSIZE)

  Select PeekL(*receive_buffer)
    Case #SERVER_verif
      Print("Login : ")
      login = Input()
      Print("Mot de passe : ")
      pass = Input()
      SendEncodedMessageToServer(Connexion, #CLIENT_verif, login+Chr(221)+pass)
    Case #SERVER_refus
      PrintN("Identification refus"+Chr(130)+"e")
      Print("Login : ")
      login = Input()
      Print("Mot de passe : ")
      pass = Input()
      SendEncodedMessageToServer(Connexion, #CLIENT_verif, login+Chr(221)+pass)
  EndSelect

  FillMemory(*receive_buffer, #RECEIVEBUFFERSIZE)
  FillMemory(*receive_buffer_e, 1.4*#RECEIVEBUFFERSIZE)
EndProcedure

Init()
Main()
End

Procedure Main()
  If *receive_buffer = 0 Or *receive_buffer_e = 0 Or *send_buffer = 0 Or *send_buffer_e = 0
    MessageRequester("Erreur AllocateMemory()", "Impossible d'allouer la mémoire nécessaire.",0)
    End
  EndIf
  Global Ip.s, Port.l, Connexion
  Frame("Client MMORPG v"+#VERSION+" - deeph")
  PrintN("")
  Repeat
    Print("Ip : ")
    Ip = Input()
    PrintN("")
    Print("Port : ")
    Port = Val(Input())
    PrintN("")
  Until Port > 0 And Port < 65000
  Connexion = OpenNetworkConnection(Ip, Port)
  If Connexion
    PrintN(FormatDate("%hh:%ii | ", Date())+"Connexion "+Chr(133)+" "+Ip+":"+Str(Port)+" r"+Chr(130)+"ussis")
  Else
    PrintN(FormatDate("%hh:%ii | ", Date())+"Impossible de se connecter au serveur")
    End
  EndIf
  PrintN("")

  Repeat
    Select NetworkClientEvent(Connexion)
      Case #PB_NetworkEvent_Data
        ReceiveEncodedData(Connexion)
    EndSelect
    Delay(5)
  ForEver
EndProcedure

Procedure Frame(message.s)
  PrintN(Chr(201)+Left(str, Len(message)+2)+Chr(187))
  PrintN(Chr(186)+" "+message+" "+Chr(186))
  PrintN(Chr(200)+Left(str, Len(message)+2)+Chr(188))
EndProcedure
Dernière modification par deeph le mar. 13/avr./2010 12:25, modifié 2 fois.
deeph
Messages : 33
Inscription : lun. 20/juil./2009 11:04
Contact :

Re: [RESOLU] Problème connexion client/serveur

Message par deeph »

Le serveur un peu plus optimisé (effectivement les maps facilitent beaucoup de choses :)) :

Code : Tout sélectionner

EnableExplicit
#VERSION = "0.1"
#RECEIVEBUFFERSIZE = 10000
#SENDBUFFERSIZE = 10000

Enumeration 42
  #SERVER_verif
  #SERVER_valid
  #SERVER_refus
  #SERVER_welcome
  #SERVER_disconnect
  #CLIENT_verif
  #CLIENT_speak
  #CLIENT_list
EndEnumeration

Structure t_client
  ip.l
  timer.l
EndStructure

Global NewMap t_client.t_client()

Structure client
  login.s
  pass.s
  ip.l
  timer.l
EndStructure

Global NewMap client.client()
Global *receive_buffer.l = AllocateMemory(#RECEIVEBUFFERSIZE)
Global *receive_buffer_e.l = AllocateMemory(1.4*#RECEIVEBUFFERSIZE)
Global *send_buffer.l = AllocateMemory(#SENDBUFFERSIZE)
Global *send_buffer_e.l = AllocateMemory(1.4*#SENDBUFFERSIZE)

Declare Main()
Declare Frame(message.s)
Declare CheckDatabaseUpdate(Database.l, Query.s)

Enumeration
  #Server
  #DataBase
EndEnumeration

Declare Init()

Procedure Init()
  If InitNetwork()=0
    MessageRequester("Erreur InitNetwork()", "Impossible d'initialiser le reseau.",0)
    End
  EndIf

  If OpenConsole() = 0
    MessageRequester("Erreur OpenConsole()", "Impossible d'ouvrir la console.")
    End
  EndIf

  ConsoleTitle ("Serveur MMORPG v"+#VERSION)

  UseSQLiteDatabase()

  Define i.l

  Global str.s
  For i = 1 To 80
    str = str + Chr(205)
  Next
EndProcedure

Declare SendEncodedMessage(ClientID.l, type.l, message.s)
Declare ReceiveEncodedData(ClientID.l)

Procedure SendEncodedMessage(ClientID.l, type.l, message.s)
  PokeL(*send_buffer, type)
  If message <> ""
    PokeS(*send_buffer+4, message)
  EndIf
  Base64Encoder(*send_buffer, #SENDBUFFERSIZE, *send_buffer_e, 1.4*#SENDBUFFERSIZE)
  SendNetworkData(ClientID, *send_buffer_e, 1.4*#SENDBUFFERSIZE)
  FillMemory(*send_buffer, #SENDBUFFERSIZE)
  FillMemory(*send_buffer_e, 1.4*#SENDBUFFERSIZE)
EndProcedure

Procedure ReceiveEncodedData(ClientID.l)
  Protected result.l = 0, message.s

  If FindMapElement(t_client(), Str(ClientID))
    Repeat
      result = ReceiveNetworkData(ClientID, *receive_buffer_e, 1.4*#RECEIVEBUFFERSIZE)
    Until result = 1.4*#RECEIVEBUFFERSIZE
    Base64Decoder(*receive_buffer_e, 1.4*#RECEIVEBUFFERSIZE, *receive_buffer, #RECEIVEBUFFERSIZE)
    Select PeekL(*receive_buffer)
      Case #CLIENT_verif
        AddMapElement(client(), Str(ClientID))
        message = PeekS(*receive_buffer+4)
        client()\login = Left(message, FindString(message, Chr(221), 1)-1)
        client()\pass = Right(message, Len(message)-FindString(message, Chr(221), 1))
        client()\ip = t_client()\ip
        client()\timer = ElapsedMilliseconds() + 600000
        PrintN(FormatDate("%hh:%ii | ", Date())+"Login : "+client()\login)
        PrintN(FormatDate("%hh:%ii | ", Date())+"Mot de passe : "+client()\pass)
        If DatabaseQuery(#DataBase, "SELECT * FROM player WHERE login = '"+client()\login+"' AND pass = '"+MD5Fingerprint(@client()\pass, Len(client()\pass))+"'")
          If NextDatabaseRow(#DataBase)
            PrintN(FormatDate("%hh:%ii | ", Date())+"Identification valid"+Chr(130)+"e")
            ;envoyer confirmation
            DeleteMapElement(t_client(), Str(ClientID))
          Else
            PrintN(FormatDate("%hh:%ii | ", Date())+"Identification refus"+Chr(130)+"e")
            SendEncodedMessage(ClientID, #SERVER_refus, "")
            DeleteMapElement(client(), Str(ClientID))
          EndIf
          FinishDatabaseQuery(#DataBase)
        Else
          PrintN(FormatDate("%hh:%ii | ", Date())+"Identification refus"+Chr(130)+"e")
          SendEncodedMessage(ClientID, #SERVER_refus, "")
          DeleteMapElement(client(), Str(ClientID))
        EndIf
      EndSelect
    FillMemory(*receive_buffer, #RECEIVEBUFFERSIZE)
    FillMemory(*receive_buffer_e, 1.4*#RECEIVEBUFFERSIZE)
  ElseIf FindMapElement(client(), Str(ClientID))
    client()\timer = ElapsedMilliseconds() + 600000
    Repeat
      result = ReceiveNetworkData(ClientID, *receive_buffer_e, 1.4*#RECEIVEBUFFERSIZE)
    Until result = 1.4*#RECEIVEBUFFERSIZE
    Base64Decoder(*receive_buffer_e, 1.4*#RECEIVEBUFFERSIZE, *receive_buffer, #RECEIVEBUFFERSIZE)
    ; etc...
    FillMemory(*receive_buffer, #RECEIVEBUFFERSIZE)
    FillMemory(*receive_buffer_e, 1.4*#RECEIVEBUFFERSIZE)
  EndIf
EndProcedure

Init()
Main()
End

Procedure Main()
  If *receive_buffer = 0 Or *receive_buffer_e = 0 Or *send_buffer = 0 Or *send_buffer_e = 0
    MessageRequester("Erreur AllocateMemory()", "Impossible d'allouer la mémoire nécessaire.",0)
    End
  EndIf
  ExamineIPAddresses()
  Global Ip.l = NextIPAddress(), Port.l
  Frame("Serveur MMORPG v"+#VERSION+" - deeph")
  PrintN("")
  Repeat
    Print("Port : ")
    Port = Val(Input())
    PrintN("")
  Until Port > 0 And Port < 65000
  If CreateNetworkServer(#Server, Port)
    PrintN(FormatDate("%hh:%ii | ", Date())+"Serveur "+IPString(Ip)+":"+Str(Port)+" lanc"+Chr(130))
    If OpenDatabase(#DataBase, "mmorpg.sqlite", "", "")
      PrintN(FormatDate("%hh:%ii | ", Date())+"Base de donn"+Chr(130)+"e ouverte")
    Else
      PrintN(FormatDate("%hh:%ii | ", Date())+"Impossible d'ouvrir la base de donn"+Chr(130)+"e : "+DatabaseError())
      End
    EndIf
  Else
    PrintN(FormatDate("%hh:%ii | ", Date())+"Impossible de lancer le serveur")
    End
  EndIf

  Repeat
    Select NetworkServerEvent()
      Case #PB_NetworkEvent_Connect
        AddMapElement(t_client(), Str(EventClient()))
        t_client()\ip = GetClientIP(EventClient())
        t_client()\timer = ElapsedMilliseconds() + 10000
        PrintN(FormatDate("%hh:%ii | ", Date())+"Tentative de connexion au serveur")
        SendEncodedMessage(EventClient(), #SERVER_verif, "")
      Case #PB_NetworkEvent_Data
        ReceiveEncodedData(EventClient())
      Case #PB_NetworkEvent_Disconnect
        DeleteMapElement(client(), Str(EventClient()))
    EndSelect
    ResetMap(t_client())
    While NextMapElement(t_client())
      If t_client()\timer < ElapsedMilliseconds()
        PrintN(FormatDate("%hh:%ii | ", Date())+"Timeout du client temporaire n"+Chr(176)+MapKey(t_client()))
        DeleteMapElement(t_client(), MapKey(t_client()))
      EndIf
    Wend
    Delay(5)
  ForEver
EndProcedure

Procedure Frame(message.s)
  PrintN(Chr(201)+Left(str, Len(message)+2)+Chr(187))
  PrintN(Chr(186)+" "+message+" "+Chr(186))
  PrintN(Chr(200)+Left(str, Len(message)+2)+Chr(188))
EndProcedure

Procedure CheckDatabaseUpdate(Database.l, Query.s)
  Define result.l = DatabaseUpdate(Database, Query)
  If result = 0
    PrintN(DatabaseError())
  EndIf
  ProcedureReturn result
EndProcedure
Dernière modification par deeph le mar. 13/avr./2010 12:25, modifié 1 fois.
Cls
Messages : 620
Inscription : mer. 22/juin/2005 8:51
Localisation : Nantes

Re: [RESOLU] Problème connexion client/serveur

Message par Cls »

Bien joué ;)

Du coup même pas encore eu le temps de tester :(
Répondre