Page 1 sur 1

Network client server code et questions ;)

Publié : dim. 13/avr./2008 13:39
par Le psychopathe
Bonjour
Voilà j'ai un mini chat qui fonctionne mais je suis un peu perdus sur divers points.
Un thread et une procedure, quelle est la difference ?
Ensuite comment créer une boucle pour chaque client sur le server car après il faut quand même récupérer les event ;)

Voilà le code exemple retravaillé un petit peu :
Chat 0.0001 ^^
Dîtes moi tout ce qui ne va pas, les amelioration à apporter ou autre ;)
merci beaucoup d'avance

Code : Tout sélectionner

;
; ------------------------------------------------------------
;
;                      Network (Client)
;
;                           Le psychopathe
;
; ------------------------------------------------------------
;


Enumeration
  #Window_0
EndEnumeration

;- Gadget Constants
;
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("127.0.0.1", Port)
SendNetworkString(ConnectionID, "Newclient")
envois = envois +1
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))                     
                    EndSelect
             
             EndSelect

Until EventID = #PB_Event_CloseWindow

  
  CloseNetworkConnection(ConnectionID)
Else
  MessageRequester("PureBasic - Client", "Can't find the server (Is it launched ?).", 0)
EndIf
  
End   
------------------------------------------------

Code : Tout sélectionner



;
; ------------------------------------------------------------
;
;                      Network (server)
;
;                           Le psychopathe
;
; ------------------------------------------------------------
;


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")
  If PeekS(*buffer) = "Newclient"
  AddElement(client())
  client() = ClientID
  EndIf
  
  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 !", 0)
  
        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   

Publié : dim. 13/avr./2008 20:33
par Oliv
Je n'ai pas le temps de regarder tes codes mais l'avantage des threads est qu'ils sont executés en parallèle de ton programme principal. Il faut cependant faire attention aux ressources partagées entre les threads et ton programme en utilisant des mutex().
Pour la récupération des events, tu as la commande clientID qui est faite pour savoir quel client a envoyé le paquet.

Publié : dim. 13/avr./2008 22:30
par cha0s
jete un coup d'oeil au socket, sa n'engage que moi mais je trouve sa plus performant que la lib de pure :
http://www.purebasic.fr/english/viewtop ... ket+server

Publié : dim. 13/avr./2008 22:52
par Le psychopathe
cha0s a écrit :jete un coup d'oeil au socket, sa n'engage que moi mais je trouve sa plus performant que la lib de pure :
http://www.purebasic.fr/english/viewtop ... ket+server
@oliv : j'ai déjà utilisé cf source ci dessus pour le ClientID
@ chaos lol c'est compliqué je vais regardé mais c'est costaud

Publié : lun. 14/avr./2008 7:27
par cha0s
c'est surtout beaucoup d'initialisation

tu charge winsock si tu est sous windows

Code : Tout sélectionner

  ; Initialize Winsock.
  wsaData.WSADATA
  iResult = WSAStartup_($101, @wsaData)

  If iResult <> #NO_ERROR
    PrintN("Error at WSAStartup()")
  EndIf 
ensuite tu crée ton socket

Code : Tout sélectionner

  ; Create a socket.
  serversocket = socket_(#AF_INET, #SOCK_STREAM, #IPPROTO_TCP)
  If serversocket = #INVALID_SOCKET
    PrintN("Error at socket(): " + Str(WSAGetLastError_()))
    WSACleanup_()
    End
  EndIf 
(les fonctions qui commence par "WSA" sont seulement pour windows)

tu charge ta configuration

Code : Tout sélectionner

  *ptr = service.sockaddr_in
 
  service\sin_family = #AF_INET
  service\sin_addr = inet_addr_("127.0.0.1");adresse ip
  service\sin_port = htons_(6667) ;port

ensuite deux cas se presente

-serveur
tu doit utiliser bind pour ecouter l'adresse 127.0.0.1:6667

Code : Tout sélectionner

  If bind_(serversocket, *ptr, SizeOf(sockaddr_in)) = #SOCKET_ERROR
    PrintN("bind() failed.")
    closesocket_(serversocket)
    End
  EndIf 
tu definit le nombre de client maximum dans la file d'attente

Code : Tout sélectionner

  If listen_(serversocket, 255) = #SOCKET_ERROR ;ici 255 client max
    CloseSocket_(clientsocket)
    WSACleanup_()
    PrintN("Error listening on socket.")
    End
  EndIf 
apres il te suffit d'attendre que les clients se connecte

Code : Tout sélectionner

  AcceptSocket = #SOCKET_ERROR
  While AcceptSocket = #SOCKET_ERROR
    AcceptSocket = accept_(serversocket, #NULL, #NULL)
    If acceptsocket > 0
      clientsocket = acceptsocket ;apres sa tu peut crée ton thread avec clientsocket en parametre
    EndIf
  Wend 


pour ton client tu te connecte

Code : Tout sélectionner

  If connect_(clientsocket, *Ptr, SizeOf(sockaddr_in)) = #SOCKET_ERROR
    PrintN("Failed to connect")
    CloseSocket_(clientsocket)
    WSACleanup_()
    End
  EndIf 

apres pour les deux c'est la meme chose

pour recevoir :
(si le socket est bloquant recv bloque jusque renvoyer quelque chose sinon il renvoie -1 en boucle tant qu'il na pas recue un packet)

Code : Tout sélectionner

recv_( clientsocket, @recvbuf, 32, 0) 

pour envoyer

Code : Tout sélectionner

bytesSent = send_( clientsocket, @sendbuf, Len(sendbuf), 0 ) 

et voila, sur linux il faut declarer les constantes et utiliser close_ a la place de closesocket_.


maintenant tu est incolable sur les sockets en mode connecté.
PS : Je demande pardon a vos yeux a propos de mon français. :p

Publié : lun. 14/avr./2008 8:24
par lionel_om
Ca me rappelle mes TPs de réseau de l'an dernier...

Lio (nostalgique, ou pas...)

Publié : lun. 14/avr./2008 10:26
par Le psychopathe
Comment envoyer des informations à un thread déjà lancé.
Car je veux gerer 10 clients dans chaque thread sur le server.
Alors comment ajouter un client dans un thread et après faire pour que les evenements server soit bien geré dans le thread 1 et 2 par exemple :)



Squellete :

Code : Tout sélectionner


procedure receveivedonnees()
xxxxxx
xxxxxx
endprocedure

create thread(receveivedonnees(),(clientid)

 Repeat
      
    SEvent = NetworkServerEvent()
  
    If SEvent
    
      
  
      Select SEvent
         
      
      
        Case 1
          MessageRequester("PureBasic - Server", "A new client has connected ! " +Str(EventClient()), 0)
          AddElement(client())
        client() = EventClient()
donc là on ajoute les clients dans la liste

case 2
ici on envoit au thread déjà lancé le clientID <<< Mais j'y arrive pas >>>>

------------------------------------------------------------------------------

Publié : lun. 14/avr./2008 11:34
par cha0s
une variable en global est accessible partout dans ton programme donc aussi dans le thread.

Publié : lun. 14/avr./2008 19:23
par Le psychopathe
En effet je eu l'étincelle juste avant que tu me réponde et là j'ai bien avancé ;)