Network Chat

Vous débutez et vous avez besoin d'aide ? N'hésitez pas à poser vos questions
Avatar de l’utilisateur
Le psychopathe
Messages : 764
Inscription : jeu. 03/mars/2005 19:23

Network Chat

Message par Le psychopathe »

Bonjour all
Suite à tous les problèmes avec la lib network, je propose une première ébauche d'un chat.
Je souhaiterai que les plus avancés corrigent mes erreurs et me donnent des ficelles.
J'ai un bug quand un client se déconnecte et se reconnecte.
Sinon c'est normal que cela soit des request dans la boucle, je sais ça bloque mais c'est juste pour moi ^^
Allez assez parler que le code commence mdr

Code : Tout sélectionner

;
; ------------------------------------------------------------
;
;   Le psychopatathe
;
;    chat v0.00000000001
;    Serveur
; ------------------------------------------------------------
;

If InitNetwork() = 0
  MessageRequester("Error", "Can't initialize the network !", 0)
  End
EndIf

Port = 6831
Global ID, ClientID, NewList client.l()


  



Procedure ReceiveData(ClientID) 
  BufferSize = 1024 
  *Buffer = AllocateMemory(BufferSize)
  Result = ReceiveNetworkData(ClientID, *Buffer, BufferSize)
  SendNetworkString(ClientID,"reçu")
  
  
  ResetList(client())
  While NextElement(client())
  Debug ClientID
  Debug client()
  If ClientID <> client()
  SendNetworkString(client(),"client " + Str(ClientID) + " : "+ PeekS(*buffer))
  EndIf
  Wend
  FreeMemory(*Buffer)
  EndProcedure 
 




If CreateNetworkServer(0, Port)

  MessageRequester("PureBasic - Server", "Server created (Port "+Str(Port)+").", 0)
  
  Repeat
      
    SEvent = NetworkServerEvent()
  
    If SEvent
    
      ClientID = EventClient()
  
      Select SEvent
         
      
      
        Case 1
          MessageRequester("PureBasic - Server", "A new client has connected ! " +Str(ClientID), 0)
          AddElement(client())
        client() = ClientID
        Case 2
        
        ReceiveData(ClientID)
                       
                  Case 3
          MessageRequester("PureBasic - Server", "Client "+Str(ClientID)+" has send a file via the network !", 0)
         
  
        Case 4
          MessageRequester("PureBasic - Server", "Client "+Str(ClientID)+" has closed the connexion...", 0)
          
    
      EndSelect
    EndIf
    
  Until Quit = 1 
  
  MessageRequester("PureBasic - Server", "Click to quit the server.", 0)
  
  CloseNetworkServer(0)
Else
  MessageRequester("Error", "Can't create the server (port in use ?).", 0)
EndIf

  
End   
---------------------

Code : Tout sélectionner

;
; ------------------------------------------------------------
;
;   Le psychopatathe
;
;    chat v0.00000000001
;    Client
; ------------------------------------------------------------
;


Enumeration
  #Window_0
EndEnumeration


Enumeration
  #Listview_0
  #String_0
  #Button_0
EndEnumeration

Global envois
envois = 0

Procedure Open_Window_0()
  If OpenWindow(#Window_0, 216, 0, 481, 250, "New window ( 0 )",  #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_TitleBar )
    If CreateGadgetList(WindowID(#Window_0))
      ListViewGadget(#Listview_0, 10, 10, 460, 200)
      StringGadget(#String_0, 10, 220, 300, 20, "")
      ButtonGadget(#Button_0, 330, 220, 140, 20, "Envoyer")
      
    EndIf
  EndIf
EndProcedure


Procedure ReceiveData(Connection) 
  BufferSize = 1024 
  *Buffer = AllocateMemory(BufferSize) 
  Result = ReceiveNetworkData(Connection, *Buffer, BufferSize)
  If PeekS(*buffer) = "[reçu]"
  envois = envois - 1
  If envois > 0
  AddGadgetItem(#Listview_0, -1,"Information : Le message n'a pas pu être envoyé")
  envois = 0
  EndIf
  Else
  AddGadgetItem(#Listview_0, -1,PeekS(*Buffer)) 
  EndIf
  FreeMemory(*Buffer) 
  EndProcedure 


open_window_0()

If InitNetwork() = 0
  MessageRequester("Error", "Can't initialize the network !", 0)
  End
EndIf

Port = 6831

ConnectionID = OpenNetworkConnection("128.89.35.9", Port)
If ConnectionID
Repeat

SEvent = NetworkClientEvent(ConnectionID)

If SEvent
    
      Select SEvent
      
       Case #PB_NetworkEvent_Data 
       ReceiveData(ConnectionID)
        EndSelect
        EndIf
        
        
       EventID = WindowEvent()
            Select EventID
                
                Case #PB_Event_Gadget
                    
                    Select EventGadget()
                         
                         Case #Button_0
                         SendNetworkString(ConnectionID, GetGadgetText(#String_0))
                         AddGadgetItem(#Listview_0, -1, "Moi : " + GetGadgetText(#String_0)) 
                         envois = envois +1                    
                    EndSelect
             
             EndSelect

Until EventID = #PB_Event_CloseWindow

  
  CloseNetworkConnection(ConnectionID)
Else
  MessageRequester("PureBasic - Client", "Can't find the server (Is it launched ?).", 0)
EndIf
  
End   
Est ce la solution de créer un nouveau thread quand un client lag. Car c'est la solution que j'ai adopté mais j'ai peur que cela parte en vrille après. voilà merci d'avance à vous
Cls
Messages : 620
Inscription : mer. 22/juin/2005 8:51
Localisation : Nantes

Message par Cls »

Salut,

Perso pour tout ce qui est réseau, j'adopte le fonctionnement suivant :
  • Réception de données -> procédure synchrones bloquantes (1 seul peut envoyer en même temps)
  • Envoi de données -> procédure d'envoi multi threadée (plusieurs requêtes peuvent partir en même temps)
Ce principe permet de ne pas bloquer le réseau si l'un des clients ne répond pas.

Concernant ton code, je te conseille de typer tes packets de données en ajoutant un octet en début de packet par exemple. De même je te déconseille d'utiliser les SendNetworkString (trop gourmant) mais plutôt de créer des packets avec un AllocateMemory puis de les envoyer avec SendNetworkData. Tes packets peuvent être forgés avec des PokeL/PokeS. Je te mettrai un exemple tout à l'heure.

Le code est un peu compliqué mais ça permet de gagner en performance (et au niveau réseau c'est important) ;)
Avatar de l’utilisateur
Le psychopathe
Messages : 764
Inscription : jeu. 03/mars/2005 19:23

Message par Le psychopathe »

J'ai pas tout compris mais si tu me poste un code ;)
Je te remercie. Car en network il y a pas grand monde qui y touche ici.
Cls
Messages : 620
Inscription : mer. 22/juin/2005 8:51
Localisation : Nantes

Message par Cls »

Je viens de poster un morceau de code sur le topic suivant : http://www.purebasic.fr/french/viewtopi ... 0574#90574

Désolé ce n'est pas le code complet mais il te permettra de trouver quelques idées.
Anonyme

Message par Anonyme »

Idem ici :


Serveur :

Code : Tout sélectionner

Structure TEMPORALY_CLIENTS
  ID.l
  IP$
  TTL.l
  RequeteTimer.l
  *Buffer.l
EndStructure

Global NewList TClient.TEMPORALY_CLIENTS()



Structure CLIENTS
  Name$
  ID.l
  IP$
  RequeteTimer.l
  *Buffer.l
EndStructure

Global NewList Client.CLIENTS()














SERVER_NAME$ = ""
PORT.l = 6832


#SERVER_SEND_ARE_YOU_GOOD_CLIENT = 1
#CLIENT_SEND_IAM_GOOD_CLIENT = 2
#SERVER_SEND_WHAT_IS_YOUR_NAME = 3
#CLIENT_SEND_MY_NAME_IS = 4









InitNetwork()

If CreateNetworkServer(0, PORT)
  Else
    MessageRequester("Erreur","Impossible de créer le serveur sur le port :"+Str(PORT))
EndIf 



Declare GestionClient()

OpenConsole()



Repeat
GestionClient()
ForEver



CloseNetworkServer(0)
End 








Procedure SendMessagei(ClientID,Message.l)
    *Question = AllocateMemory(4)
    PokeL(*Question,Message)
    SendNetworkData(ClientID,*Question,4)
    FreeMemory(*Question)
EndProcedure








Procedure GestionClient()
*Buffer.l = #Null

SEvent = NetworkServerEvent()
 





If SEvent = #PB_NetworkEvent_Connect
  AddElement(TClient())
  TClient()\ID  = EventClient()
  TClient()\TTL = ElapsedMilliseconds() + 10000
  TClient()\IP$ = IPString(GetClientIP(TClient()\ID))
  TClient()\Buffer = AllocateMemory(1000)
    PrintN("Tentative de connection("+TClient()\IP$+") au serveur...")
    
  
    ; On questionne le client pour savoir il est valide ( pas un client bidon par ex...)  
    SendMessagei(TClient()\ID,#SERVER_SEND_ARE_YOU_GOOD_CLIENT)
    
    
EndIf 


If SEvent=#PB_NetworkEvent_Data
PrintN("Préparation à la recepetion de données")
      
      
      
ClientID = EventClient()


;*************************************
;On parcours les clients temporaires
;*************************************
          ForEach TClient()
          
          
              If TClient()\ID  = ClientID 
                PrintN("Recepetion de données du client ("+TClient()\IP$+")")
                    ReceiveNetworkData(ClientID,TClient()\Buffer,1000)
                    Break
                      EndIf 
                   
                      
          Next 

          If ListSize(TClient())>0
          
                  If TClient()\Buffer<>#Null
                  
                  Message = PeekL(TClient()\Buffer)
                  
                  If Message = #CLIENT_SEND_IAM_GOOD_CLIENT
                    PrintN("Connection en cour...")
                    
                    AddElement(Client())
                    Client()\ID  = TClient()\ID
                    Client()\IP$ = TClient()\IP$ 
                    
                    DeleteElement(TClient(),1)
                    
                  EndIf 
                  
                  
                  Else
                    PrintN("Recepetion de données invalides!")
                  EndIf 
          EndIf 
;*************************************
;
;*************************************





;*************************************
;On parcours les clients 
;*************************************

        ForEach Client()
        
                If Client()\ID  = ClientID 
                   Client()\Buffer = AllocateMemory(1000)
                    ReceiveNetworkData(ClientID,Client()\Buffer,1000)
                      Break
                        EndIf 
        
        Next 


        If Client()\Buffer<>#Null
        
            Message = PeekL(Client()\Buffer)
            
            If Message = #CLIENT_SEND_MY_NAME_IS
                  Client()\Name$ = PeekS(Client()\Buffer+4)
                  PrintN("Le client c'est identifie sous le pseudo :" +Client()\Name$ )
            EndIf 
        
    
        EndIf 



EndIf 






ForEach TClient()
    If TClient()\TTL < ElapsedMilliseconds()
      DeleteElement(TClient())
        PrintN("Temps de reponse du client trop long.")
          Break
          Else
         
         If TClient()\RequeteTimer < ElapsedMilliseconds()
              TClient()\RequeteTimer = ElapsedMilliseconds() + 500
                SendMessagei(TClient()\ID,#SERVER_SEND_ARE_YOU_GOOD_CLIENT)
               PrintN("Envois requete au client ("+TClient()\IP$+")...") 
          EndIf 
     EndIf
Next 









ForEach Client()
; On demande le pseudo au client
If Client()\Name$ = "" And Client()\RequeteTimer<ElapsedMilliseconds()
  Client()\RequeteTimer = ElapsedMilliseconds() + 500
  SendMessagei(Client()\ID,#SERVER_SEND_WHAT_IS_YOUR_NAME)
EndIf 


Next 


EndProcedure

Client :

Code : Tout sélectionner

#SERVER_SEND_ARE_YOU_GOOD_CLIENT = 1
#CLIENT_SEND_IAM_GOOD_CLIENT = 2
#SERVER_SEND_WHAT_IS_YOUR_NAME = 3
#CLIENT_SEND_MY_NAME_IS = 4



InitNetwork()


i = OpenNetworkConnection("127.0.0.1",6832)
Name$ = "Bob l'eponge"

OpenConsole()


Repeat

Event = NetworkClientEvent(i) 

If event = #PB_NetworkEvent_Data
*Buffer = AllocateMemory(1000)
  ReceiveNetworkData(i, *Buffer, 1000)
  Result = PeekL(*Buffer)
  FreeMemory(*Buffer)
  *Buffer = AllocateMemory(4)

  Select Result
  
  Case #SERVER_SEND_ARE_YOU_GOOD_CLIENT
    PokeL(*Buffer,#CLIENT_SEND_IAM_GOOD_CLIENT)
    SendNetworkData(i,*Buffer,4)
  Case #SERVER_SEND_WHAT_IS_YOUR_NAME
    FreeMemory(*Buffer)
    AllocateMemory(4+Len(Name$))
    PokeL(*Buffer,#CLIENT_SEND_MY_NAME_IS)
    PokeS(*Buffer+4,Name$)
    SendNetworkData(i,*Buffer,MemorySize(*Buffer))
    
  
  EndSelect

  FreeMemory(*Buffer)


EndIf 




ForEver




C'est une ébauche , une application réseau est complexe à réalisé , les commandes PB de base permet seulement la communication , à toi de gérer la relation client/serveur.
Avatar de l’utilisateur
Le psychopathe
Messages : 764
Inscription : jeu. 03/mars/2005 19:23

Message par Le psychopathe »

Cpl.Bator a écrit :Idem ici :


Serveur :

Code : Tout sélectionner

Structure TEMPORALY_CLIENTS
  ID.l
  IP$
  TTL.l
  RequeteTimer.l
  *Buffer.l
EndStructure

Global NewList TClient.TEMPORALY_CLIENTS()



Structure CLIENTS
  Name$
  ID.l
  IP$
  RequeteTimer.l
  *Buffer.l
EndStructure

Global NewList Client.CLIENTS()














SERVER_NAME$ = ""
PORT.l = 6832


#SERVER_SEND_ARE_YOU_GOOD_CLIENT = 1
#CLIENT_SEND_IAM_GOOD_CLIENT = 2
#SERVER_SEND_WHAT_IS_YOUR_NAME = 3
#CLIENT_SEND_MY_NAME_IS = 4









InitNetwork()

If CreateNetworkServer(0, PORT)
  Else
    MessageRequester("Erreur","Impossible de créer le serveur sur le port :"+Str(PORT))
EndIf 



Declare GestionClient()

OpenConsole()



Repeat
GestionClient()
ForEver



CloseNetworkServer(0)
End 








Procedure SendMessagei(ClientID,Message.l)
    *Question = AllocateMemory(4)
    PokeL(*Question,Message)
    SendNetworkData(ClientID,*Question,4)
    FreeMemory(*Question)
EndProcedure








Procedure GestionClient()
*Buffer.l = #Null

SEvent = NetworkServerEvent()
 





If SEvent = #PB_NetworkEvent_Connect
  AddElement(TClient())
  TClient()\ID  = EventClient()
  TClient()\TTL = ElapsedMilliseconds() + 10000
  TClient()\IP$ = IPString(GetClientIP(TClient()\ID))
  TClient()\Buffer = AllocateMemory(1000)
    PrintN("Tentative de connection("+TClient()\IP$+") au serveur...")
    
  
    ; On questionne le client pour savoir il est valide ( pas un client bidon par ex...)  
    SendMessagei(TClient()\ID,#SERVER_SEND_ARE_YOU_GOOD_CLIENT)
    
    
EndIf 


If SEvent=#PB_NetworkEvent_Data
PrintN("Préparation à la recepetion de données")
      
      
      
ClientID = EventClient()


;*************************************
;On parcours les clients temporaires
;*************************************
          ForEach TClient()
          
          
              If TClient()\ID  = ClientID 
                PrintN("Recepetion de données du client ("+TClient()\IP$+")")
                    ReceiveNetworkData(ClientID,TClient()\Buffer,1000)
                    Break
                      EndIf 
                   
                      
          Next 

          If ListSize(TClient())>0
          
                  If TClient()\Buffer<>#Null
                  
                  Message = PeekL(TClient()\Buffer)
                  
                  If Message = #CLIENT_SEND_IAM_GOOD_CLIENT
                    PrintN("Connection en cour...")
                    
                    AddElement(Client())
                    Client()\ID  = TClient()\ID
                    Client()\IP$ = TClient()\IP$ 
                    
                    DeleteElement(TClient(),1)
                    
                  EndIf 
                  
                  
                  Else
                    PrintN("Recepetion de données invalides!")
                  EndIf 
          EndIf 
;*************************************
;
;*************************************





;*************************************
;On parcours les clients 
;*************************************

        ForEach Client()
        
                If Client()\ID  = ClientID 
                   Client()\Buffer = AllocateMemory(1000)
                    ReceiveNetworkData(ClientID,Client()\Buffer,1000)
                      Break
                        EndIf 
        
        Next 


        If Client()\Buffer<>#Null
        
            Message = PeekL(Client()\Buffer)
            
            If Message = #CLIENT_SEND_MY_NAME_IS
                  Client()\Name$ = PeekS(Client()\Buffer+4)
                  PrintN("Le client c'est identifie sous le pseudo :" +Client()\Name$ )
            EndIf 
        
    
        EndIf 



EndIf 






ForEach TClient()
    If TClient()\TTL < ElapsedMilliseconds()
      DeleteElement(TClient())
        PrintN("Temps de reponse du client trop long.")
          Break
          Else
         
         If TClient()\RequeteTimer < ElapsedMilliseconds()
              TClient()\RequeteTimer = ElapsedMilliseconds() + 500
                SendMessagei(TClient()\ID,#SERVER_SEND_ARE_YOU_GOOD_CLIENT)
               PrintN("Envois requete au client ("+TClient()\IP$+")...") 
          EndIf 
     EndIf
Next 









ForEach Client()
; On demande le pseudo au client
If Client()\Name$ = "" And Client()\RequeteTimer<ElapsedMilliseconds()
  Client()\RequeteTimer = ElapsedMilliseconds() + 500
  SendMessagei(Client()\ID,#SERVER_SEND_WHAT_IS_YOUR_NAME)
EndIf 


Next 


EndProcedure

Client :

Code : Tout sélectionner

#SERVER_SEND_ARE_YOU_GOOD_CLIENT = 1
#CLIENT_SEND_IAM_GOOD_CLIENT = 2
#SERVER_SEND_WHAT_IS_YOUR_NAME = 3
#CLIENT_SEND_MY_NAME_IS = 4



InitNetwork()


i = OpenNetworkConnection("127.0.0.1",6832)
Name$ = "Bob l'eponge"

OpenConsole()


Repeat

Event = NetworkClientEvent(i) 

If event = #PB_NetworkEvent_Data
*Buffer = AllocateMemory(1000)
  ReceiveNetworkData(i, *Buffer, 1000)
  Result = PeekL(*Buffer)
  FreeMemory(*Buffer)
  *Buffer = AllocateMemory(4)

  Select Result
  
  Case #SERVER_SEND_ARE_YOU_GOOD_CLIENT
    PokeL(*Buffer,#CLIENT_SEND_IAM_GOOD_CLIENT)
    SendNetworkData(i,*Buffer,4)
  Case #SERVER_SEND_WHAT_IS_YOUR_NAME
    FreeMemory(*Buffer)
    AllocateMemory(4+Len(Name$))
    PokeL(*Buffer,#CLIENT_SEND_MY_NAME_IS)
    PokeS(*Buffer+4,Name$)
    SendNetworkData(i,*Buffer,MemorySize(*Buffer))
    
  
  EndSelect

  FreeMemory(*Buffer)


EndIf 




ForEver




C'est une ébauche , une application réseau est complexe à réalisé , les commandes PB de base permet seulement la communication , à toi de gérer la relation client/serveur.
Merci, je vais regarder ça. Mais dis moi, mon code tu le trouves comment enfin plutôt ma logique pour les threads côté serveur ?
Anonyme

Message par Anonyme »

Pour un tchat , pas besoin de treads.
Avatar de l’utilisateur
Le psychopathe
Messages : 764
Inscription : jeu. 03/mars/2005 19:23

Message par Le psychopathe »

Cpl.Bator a écrit :Pour un tchat , pas besoin de treads.
Je me suis mal exprimer, si c'était des echanges de fichiers ?
Anonyme

Message par Anonyme »

dans se cas oui , faut pas bloqué l'appli.
Répondre