Page 1 sur 2

Code source d'un Tchat

Publié : sam. 06/nov./2021 13:37
par omega
Bonjour,

Je viens de perdre un code source d'un tchat que j'avais modifié puis utilisé durant plus de 2 ans.. J'ai découvert ce code sur ce forum (je crois qu'il est de Falsam). Quelqu'un pourrait m'orienter où puis-je le récupérer ? J'ai essayer la recherche mais vainement.

Merci d'avance

Re: Code source d'un Tchat

Publié : sam. 06/nov./2021 16:24
par falsam
J'avais écrit un client de tchat en Purebasic connecté à un serveur sous nodes.js. A mon avis c'est pas ça que tu cherches.

:arrow: Peut être que tu utilises ce code de Yrahen plutôt ?
https://www.purebasic.fr/french/viewtop ... 21&t=14178

Re: Code source d'un Tchat

Publié : sam. 06/nov./2021 18:57
par omega
Merci Falsam pour ce code que je viens e tester mais je ne comprends pas grand'chose sur le fonctionnement, je vois des mots en chinois affichés dans le conteneur, je ne sais pas s'il faut commencer pr le pseudo ou le message?

Re: Code source d'un Tchat

Publié : sam. 06/nov./2021 21:54
par Ar-S
Dans quel contexte tu veux utiliser un tchat ? Uniquement en PB avec un client un serveur ? En passant par PB et transitant sur une page web ? En utilisant des "utilisateurs" ? Une BDD ?

Re: Code source d'un Tchat

Publié : sam. 06/nov./2021 23:22
par omega
Bonsoir Ars

Juste un tchat pour envoyer et recevoir des messages au réel... comme tous les tchats un chat très simple...

Re: Code source d'un Tchat

Publié : dim. 07/nov./2021 7:59
par SPH
Je serais aussi intéressé par un tchat fait en PB. Un client et un serveur.
Le pire, c'est que je suis persuadé d'en avoir vu un il y a un an sur le forum... mais impossible de remettre la main dessus.

(ps : je parle bien d'un client et un serveur PB hein !)

Re: Code source d'un Tchat

Publié : dim. 07/nov./2021 8:17
par Marc56
SPH a écrit : dim. 07/nov./2021 7:59 Je serais aussi intéressé par un tchat fait en PB. Un client et un serveur.
Le pire, c'est que je suis persuadé d'en avoir vu un il y a un an sur le forum... mais impossible de remettre la main dessus.
(ps : je parle bien d'un client et un serveur PB hein !)
Dans l'aide de PB tout simplement
PureBasic - Network :wink:

Re: Code source d'un Tchat

Publié : dim. 07/nov./2021 8:21
par SPH
Je me suis mal exprimé... Je parlais d'un tchat qui envoyait et recevait des messages (et ce, du coté serveur et du coté client)
Bref, plus fonctionnel que l'exemple dans PB.

Plus "tchatien" quoi :wink:

Re: Code source d'un Tchat

Publié : dim. 07/nov./2021 14:45
par venom
SPH a écrit : dim. 07/nov./2021 7:59 Je serais aussi intéressé par un tchat fait en PB. Un client et un serveur.
Le pire, c'est que je suis persuadé d'en avoir vu un il y a un an sur le forum... mais impossible de remettre la main dessus.

(ps : je parle bien d'un client et un serveur PB hein !)

J'en ai fait un. Mais étrange je ne le retrouve pas sur le forum... :?
Après je ne sais pas si je l'ai posté, mais ça m'étonne que non.

Voilà les sources :
serveur

client
Pas tester sur les dernières versions.









@++

Re: Code source d'un Tchat

Publié : dim. 07/nov./2021 14:52
par Marc56
À partir des exemples, simplement en remplaçant les MessageRequester
Serveur

Code : Tout sélectionner

If InitNetwork() = 0
  Debug "Error - Can't initialize the network !" : End
EndIf

Port = 6832
*Buffer = AllocateMemory(1000)

If CreateNetworkServer(0, Port)
  Debug "Server - Server created (Port " + Str(Port) + ")"
  Repeat
    SEvent = NetworkServerEvent() 
    If SEvent
      ClientID = EventClient()  
      Select SEvent
          
        Case #PB_NetworkEvent_Connect
          Debug "Server - A new client has connected !"
          
        Case #PB_NetworkEvent_Data
          Debug "Server > Client " + Str(ClientID) + " has send a packet !"
          ReceiveNetworkData(ClientID, *Buffer, 1000)
          Debug "Client > " + PeekS(*Buffer, -1, #PB_UTF8)
          
        Case #PB_NetworkEvent_Disconnect
          Debug "Server - Client " + Str(ClientID)+" has closed the connection..."
          Quit = 1
          
      EndSelect
    EndIf
  Until Quit = 1  
  Debug "Server - Close connection"
  CloseNetworkServer(0)
Else
  Debug "Error - Can't create the server (port in use ?)."
EndIf

End   

Client

Code : Tout sélectionner

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

Port = 6832
IP$ = "127.0.0.1"

ConnectionID = OpenNetworkConnection(IP$, Port)
If ConnectionID
  
  Repeat
    Txt$ = InputRequester("Texte", "Vide = Quitter", "")
    SendNetworkString(ConnectionID, Txt$, #PB_UTF8)
  Until Txt$ = ""
  
  CloseNetworkConnection(ConnectionID)
Else
  Debug "Client - Can't find the server (Is it launched ?)."
EndIf

End   
Pour tester, tu lances le client, puis le serveur.
Pour quitter, ne rien mettre dans la boite InputBox

Maintenant pour en faire un tchat 2 à 2 il suffit de mixer les deux programmes en un seul, mettre deux IP
Utiliser une ListeView pour afficher le dialogue et un StringGadget pour les entrées à la place de l'InputBox
Il faudra utiliser deux ports car chaque PC sera serveur et client

On va encore me dire que je réinvente la roue, mais quoi d emieux pour entretenir les neurones ?
(sinon, il suffit d'installer un serveur IRC)
:wink:

Re: Code source d'un Tchat

Publié : dim. 07/nov./2021 19:20
par SPH
@venom : merci. Je regarde ça quand je serais sur le bon ordi.

@marc : "Maintenant pour en faire un tchat 2 à 2 il suffit de mixer les deux programmes en un seul"
c'est justement la que ça se complique. Je ne m'en suis jamais sortie...

Re: Code source d'un Tchat

Publié : dim. 07/nov./2021 20:39
par blendman
Salut

Moi, c'est un serveur php avec client pb qui m'intéresserait bien :)

L'exemple d'yraken ne fonctionne pas du tout, hélas.
Donc, si quelqu'un a un exemple avec page php ce serait bien cool.

Sinon, j'ai modifié le code de marc et tadam, tout en 1 seul fichier : serveur ou client, vous choisissez ;).

Code : Tout sélectionner

; Serveur et client MArc56 
; modifié par blendman 11.2021

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

Port = 6832
IP$ = "127.0.0.1"

; on créer une structure pour les clients
Structure sClient
  Id.i
  pseudo$
EndStructure
Global NewList Clients.sClient()

Procedure AddClient(ClientID, pseudo$)
  AddElement(clients())
  Clients()\Id = ClientID
  Clients()\pseudo$ = pseudo$
EndProcedure



If OpenWindow(0,0,0,600,400,"Tchat PB",#PB_Window_SystemMenu)
  ; on ouvre une fenêtre
  
  ;{ l'écran pour choisir serveur ou client
  ;   D'abord, j'ajoute 2 boutons, pour choisir si on est client ou server
  ButtonGadget(0,100,200,200,30,"Créer le Serveur")
  ButtonGadget(1,310,200,200,30,"Client")
  type.b = -1
  ; ensuite, on va vérifier si on clique sur server ou client
  Repeat
    event = WaitWindowEvent(1)
    eventgadget = EventGadget()
    
    Select event
      Case #PB_Event_CloseWindow
        End
        
      Case #PB_Event_Gadget
        Select eventgadget
          Case 0 ; serveur
            type = 0
            
          Case 1 ; serveur
            type = 1
        EndSelect
        
        
    EndSelect
    
  Until type >-1
  ; on supprime les gadgets
  FreeGadget(0)
  FreeGadget(1)
  
  ;}
  
  
  ; et on lance en fonction de ce qu'on a choisi
  
  
  If type = 0
    ;{ on a choisi "Serveur"
    
    ; on crée un editor pour voir les messages du serveurs
    EditorGadget(0,10,10,WindowWidth(0)-20, WindowHeight(0)-20)
    
    *Buffer = AllocateMemory(1000)
    
    If CreateNetworkServer(0, Port)
      Servertxt$+ "Server - Server created (Port " + Str(Port) + ")"+Chr(13)
      SetGadgetText(0,Servertxt$)
      
      Repeat
        event = WaitWindowEvent(1)  
        SEvent = NetworkServerEvent() 
        
        If event = #PB_Event_CloseWindow
          quit =1
        EndIf
        
        If SEvent
          ClientID = EventClient()  
          Select SEvent
              
            Case #PB_NetworkEvent_Connect
              Servertxt$+ "Server - A new client has connected !"+Chr(13)
              SetGadgetText(0,Servertxt$)
              AddClient(ClientID, "")
              
              
            Case #PB_NetworkEvent_Data
              Servertxt$+  "Server > Client " + Str(ClientID) + " has send a packet !"+Chr(13)
              taille = ReceiveNetworkData(ClientID, *Buffer, 1000)
              txt$ = PeekS(*Buffer, taille, #PB_UTF8)
              Servertxt$+ "Client > " + txt$+Chr(13)
              SetGadgetText(0,Servertxt$)
              ; puis on envoie le message à tout le monde
              ForEach Clients()
                SendNetworkString(Clients()\Id, txt$, #PB_UTF8)
              Next 
              
            Case #PB_NetworkEvent_Disconnect
              Servertxt$+ "Server - Client " + Str(ClientID)+" has closed the connection..."+Chr(13)
              SetGadgetText(0,Servertxt$)
              ; là, il faudrait supprimer le client de la liste, mais j'ai la flemme ^^. Donc, je vous laisse le faire ;)
                
          EndSelect
        EndIf
        
      Until Quit = 1  
      ; Et là, tu te casses sur mars, tululu, tu te casses sur mars....
      Servertxt$+ "Server - Close connection"+Chr(13)
      SetGadgetText(0,Servertxt$)
      
      CloseNetworkServer(0)
    Else
      Debug "Error - Can't create the server (port in use ?)."
    EndIf
    
    End  
    ;}
    
  ElseIf type = 1
    ;{ client
    
    ; D'abord, on demande le pseudo, ouais, classe
    Repeat
       pseudo$ = InputRequester("Votre pseudo", "","")
    Until  pseudo$ <> ""
    
    ; on crée un editor pour le tchat et un autre pour envoyer les message ainsi qu'un bouton.
    w = 50
    h = 30
    y = WindowHeight(0)-20-h
    EditorGadget(0,10,10,WindowWidth(0)-20, WindowHeight(0)-20-20-h, #PB_Editor_ReadOnly|#PB_Editor_WordWrap)
    ; EditorGadget(1,10,y, WindowWidth(0)-20-w, h) ; on peut envoyer des messages sur multi-lignes
    StringGadget(1,10,y, WindowWidth(0)-20-w, h, "")
    ButtonGadget(2,WindowWidth(0)-10-w,y,w,h,"Envoyer")
    
    *Buffer = AllocateMemory(1000)
    ConnectionID = OpenNetworkConnection(IP$, Port)
    
    If ConnectionID
    ; Faudrait envoyé un message spécial au serveur pour lui filer le pseudo du nouveau gusse qui s'est connected, hou pinaise.
     ; SendNetworkString(ConnectionID, pseudo$, #PB_UTF8)  
      
      Repeat
        event = WaitWindowEvent(1)
        sEvent = NetworkClientEvent(ConnectionID)
        
        Select Sevent
            
          Case #PB_NetworkEvent_Disconnect
            Servertxt$+ "Connexion arrêtée"+Chr(13)
            SetGadgetText(0,Servertxt$)
            
          Case #PB_NetworkEvent_Data   
          ; on reçoit un message, j'ai pas utilisé d'identifiants pour les messages, mais il faudrait le faire.
          ; de plus rien n'est chiffré/encrypté, hou le vilaiN.   
            taille = ReceiveNetworkData(ConnectionID, *Buffer, 1000)
            txt1$ = PeekS(*Buffer, taille, #PB_UTF8)
            Servertxt$+ txt1$+Chr(13)
            SetGadgetText(0,Servertxt$)
            
        EndSelect
        ; là, on va vérifier si on envoie un message, vu que c'est tchat. Ah ouais ? ben oui.
        Select event
          Case #PB_Event_Gadget
            Select EventGadget()
              Case 2
                If GetGadgetText(1)<> ""
                  ;Txt$ = Pseudo$ + " : "+Chr(13)+GetGadgetText(1) ; si tu veux mettre le message à la ligne
                  Txt$ = Pseudo$ + " : "+GetGadgetText(1) ; ou pas, c'est comme tu veux.
                  SendNetworkString(ConnectionID, Txt$, #PB_UTF8)
                  Txt$ = ""
                  ; on efface, car c'est mieux pour pas laisser de traces :)
                  ; ClearGadgetItems(1) ; si on utilise l'éditorgadget au lieu du string gadget, pour le multi-ligne.
                  SetGadgetText(1, "")
                EndIf
            EndSelect
            
        EndSelect
        
      Until event = #PB_Event_CloseWindow
      
      CloseNetworkConnection(ConnectionID)
      Else
        Debug "Client - Can't find the server (Is it launched ?)." ; ouais, je parle presque anglais. en fait, ça vient de l'exemple purebasic
      EndIf
    EndIf
    
    ; this is the : 
    End  
    ; beautifull friend :)
    ;}
    
  EndIf
A améliorer, mais ça me semble une base pas trop pourri :)

A+

PS : pour améliorer le truc, faudrait utiliser le canvas pour afficher les messages, comme ça, on aurait des smileys, des couleurs pour le textes, etc...
mais bon, ce sera pour une autre fois^^

Re: Code source d'un Tchat

Publié : dim. 07/nov./2021 21:33
par Ar-S
J'avais fait un mini chat ftp pour papoter avec ma femme. Un simple up/down ftp et un fichier texte qui s'up quand on envoyait.
L'autre ne fasse comparait toutes les X sec la taille du fichier et récupérait le contenu.
ça marchait bien même si c'est une technique de woualou.

Ce qui m'ennuie avec les version client/serveur en PB c'est les soucis d'IP qu'on risque de rencontrer.
Perso si je devais faire un tchat aujourd'hui, je ferai
- Un backend php/mysql pour la gestion des utilisateurs et des messages. (à voir si public ou privé donc mot de passe ou non)
- Une page API pour entrer les données envoyé en POST ou GET par PB
- Un timer pour récupérer les messages via une autre page API

Re: Code source d'un Tchat

Publié : mar. 09/nov./2021 17:03
par Marc56
blendman a écrit : dim. 07/nov./2021 20:39 ...

Code : Tout sélectionner

    If ConnectionID
    ; Faudrait envoyer un message spécial au serveur pour lui filer le pseudo du nouveau gusse qui s'est connected, hou pinaise.
     ; SendNetworkString(ConnectionID, pseudo$, #PB_UTF8)  
Oui, c'est comme cela qu'il faut faire, (je pense)
Il suffit ensuite au niveau serveur de récupérer la première ligne envoyée après la connexion et de l'affecter à Clients()\pseudo$

Je suis en train de faire un IRC basé sur ton exemple et le mien, mais en deux programmes séparés: un serveur (en trayicon) (avec fenêtre de log) et un client séparé.

J'ai buggué pas mal en me trompant dans les id de connexion... (relire, relire, relire)
Mon premier programme 'net' (décidément, PB nous facilite grandement la programmation dans tous les domaines)

:wink:

Re: Code source d'un Tchat

Publié : jeu. 11/nov./2021 11:09
par Marc56
Suite du projet: Beaucoup de choses encore à faire. Le prototype fonctionne, le réseau aussi. Il reste à faire l'alternance des couleurs pour la lisibilité et une icône d'état pour les clients (Permet de l'utiliser comme systeme ICQ) pour les anciens qui connaissent :)
Le système utilise quelques commandes IRC standard. Côté serveur, il suffit de vérifier si le premier caractère est un / alors c'est une commande. Sinon le serveur retourne le texte à tous les clients connectés. (Merci Blendman pour l'idée de la structure et de la boucle ForEach). J'ai aussi du ajouter un timer d'une seconde pour forcer le refresh des clients.
Le serveur aura aussi une version console pour tourner sur les machines linux sans interface graphique. (Je remplace la fenêtre par un fichier de log qu'ont peut afficher en scrolling avec tail -f)
Il reste encore des plantages à cause des tampons mémoire à vider après transmission et autres si une connexion n'est plus active)
Reste aussi à remplacer le ListViewGadget par un ListIconGadget pour changer les couleurs des lignes en fonction des utilisateurs et pemettre de mettre des colonnes et icônes)
Image

Si vous voulez tester/améliorer
Pour simplifier, j'ai inclu le .pbf dans le source. À vous de reséparer si vous souhaitez utiliser le Form Designer
Le serveur.
À lancer sur un seul poste.

Code : Tout sélectionner

; PB IRC Server
; Marc56 10/11/21
; Modifications blendman

; todo: fermer tous les clients en quittant

OnErrorGoto(?Global_Error)

; XIncludeFile "PB_IRC_Server.pbf"
; Form Designer for Purebasic - 6.00
; Warning: this file uses a strict syntax, if you edit it, make sure to respect the Form Designer limitation or it won't be opened again.

;
; This code is automatically generated by the FormDesigner.
; Manual modification is possible to adjust existing commands, but anything else will be dropped when the code is compiled.
; Event procedures needs to be put in another source file.
;

Enumeration FormWindow
  #Win_Server
EndEnumeration

Enumeration FormGadget
  #Log
EndEnumeration

Enumeration FormFont
  #Font_Win_Server_0
EndEnumeration

LoadFont(#Font_Win_Server_0,"Consolas", 10)

Declare ResizeGadgetsWin_Server()


Procedure OpenWin_Server(x = 10, y = 10, width = 300, height = 500)
  OpenWindow(#Win_Server, x, y, width, height, "PB IRCd", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_SizeGadget)
  CreateStatusBar(0, WindowID(#Win_Server))
  AddStatusBarField(300)
  StatusBarText(0, 0, "PB IRCd - v0.1")
  ListViewGadget(#Log, 5, 5, 290, 465)
  SetGadgetColor(#Log, #PB_Gadget_FrontColor,RGB(128,128,128))
  SetGadgetColor(#Log, #PB_Gadget_BackColor,RGB(255,255,255))
  SetGadgetFont(#Log, FontID(#Font_Win_Server_0))
EndProcedure

Procedure ResizeGadgetsWin_Server()
  Protected FormWindowWidth, FormWindowHeight
  FormWindowWidth = WindowWidth(#Win_Server)
  FormWindowHeight = WindowHeight(#Win_Server)
  ResizeGadget(#Log, 5, 5, FormWindowWidth - 10, FormWindowHeight - StatusBarHeight(0) - 12)
EndProcedure
; ------------------------------------------------- / form

Structure sClient
    ID.i
    Name$
    Connected.i
EndStructure
Global NewList Client.sClient()
Global Receive_Txt$

Procedure Monitor(Message$)
    ; Display on server
    AddGadgetItem(#Log, -1, Message$)
    ; todo: Log file
EndProcedure

Procedure Send_All(Message$)
    If Message$ <> "" : Receive_Txt$ = Message$ : EndIf
    ForEach Client()
        If Client()\Connected = 1
            SendNetworkString(Client()\ID, Receive_Txt$, #PB_UTF8)
        EndIf
    Next    
EndProcedure

OpenWin_Server()
Monitor("Starting IRC Server...")

If InitNetwork() = 0
    Monitor("Error - Can't initialize the network !")
Else
    Monitor("Network Ready")
EndIf

If CountProgramParameters() 
    Port = Val(ProgramParameter(0))
Else
    Port = 6832
EndIf
*Buffer = AllocateMemory(1000)

If Not CreateNetworkServer(0, Port)
    Monitor("Error - Can't create the server (port in use ?).")
EndIf

Monitor("Listening on port: " + Str(Port))
SetWindowTitle(#Win_Server, "PB IRCd - Running...")

Repeat
    Win_Event = WaitWindowEvent(1)
    Net_Event = NetworkServerEvent() 
    
    Select Win_Event
        Case #PB_Event_CloseWindow
            Monitor("Close connection(s)")
            CloseNetworkServer(0)
            End
            
        Case #PB_Event_SizeWindow
            ResizeGadgetsWin_Server()
    EndSelect
    
    ID_Client = EventClient() 
    If NickName$ = "" :
        NickName$ = LSet(Str(ID_Client), 8, " ") 
    EndIf
    Select Net_Event
            
        Case #PB_NetworkEvent_Connect
            Monitor(NickName$ + " : Connected.")
            AddElement(Client()) 
            With Client()
                \ID     = ID_Client
                \Name$  = NickName$
                \Connected = 1
            EndWith
            
        Case #PB_NetworkEvent_Data
            FillMemory(*Buffer, 1000)
            Nb_Octets = ReceiveNetworkData(ID_Client, *Buffer, 1000)
            Receive_Txt$ = PeekS(*Buffer, Nb_Octets, #PB_UTF8)
            If Left(Receive_Txt$, 5) = "/nick"
                NickName$ = Mid(Receive_Txt$, 6, 10)
                Client()\Name$ = NickName$
            Else
                Monitor(Receive_Txt$)
 
            EndIf
            Send_All("")
            
        Case #PB_NetworkEvent_Disconnect
            Monitor(LTrim(NickName$) + " : has quit.")
            Client()\Connected = 0
            
    EndSelect
Until Quit = 1  
Monitor("Server - Close connection")
CloseNetworkServer(0)

End   

Global_Error:
MessageRequester("Error", ErrorMessage(), 16)
Le client
On peut en lancer plusieurs sur le même poste pour tester.
Il génère au démarrage un nom aléatoire (ID_ 0 à 99) on en change ensuite.
Sur un réseau local, mettre ladresse du serveur (donc pas 127.0.0.1)
Sur Internet, il faut translater le port au niveau de la box vers la machine qui héberge le serveur
(attention: il n'y a aucune sécurité pour l'instant)

Code : Tout sélectionner

; PB IRC Client
; Marc56 10/11/21
; Modifications blendman

OnErrorGoto(?Global_Error)

; XIncludeFile "PB_IRC.pbf"
; Form Designer for Purebasic - 6.00
; Warning: this file uses a strict syntax, if you edit it, make sure to respect the Form Designer limitation or it won't be opened again.

;
; This code is automatically generated by the FormDesigner.
; Manual modification is possible to adjust existing commands, but anything else will be dropped when the code is compiled.
; Event procedures needs to be put in another source file.
;

Enumeration FormWindow
    #Win
EndEnumeration

Enumeration FormGadget
    #Dialog
    #Txt
    #Btn_Send
    #Btn_Connect
    #Btn_Quit
    #Str_Name
    #Btn_Name
    #Str_IP
    #Str_Port
    #Txt_Alias
EndEnumeration

Enumeration FormFont
    #Font_Win_0
EndEnumeration

LoadFont(#Font_Win_0,"Consolas", 10)

Declare ResizeGadgetsWin()


Procedure OpenWin(x = 0, y = 0, width = 300, height = 500)
    OpenWindow(#Win, x, y, width, height, "PB IRC", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget | #PB_Window_SizeGadget | #PB_Window_ScreenCentered)
    CreateStatusBar(0, WindowID(#Win))
    AddStatusBarField(300)
    StatusBarText(0, 0, "Ready.")
    ListViewGadget(#Dialog, 5, 65, 290, 380)
    SetGadgetFont(#Dialog, FontID(#Font_Win_0))
    StringGadget(#Txt, 5, 447, 215, 25, "")
    SetGadgetFont(#Txt, FontID(#Font_Win_0))
    ButtonGadget(#Btn_Send, 225, 447, 70, 25, "Send", #PB_Button_Default)
    SetGadgetFont(#Btn_Send, FontID(#Font_Win_0))
    DisableGadget(#Btn_Send, 1)
    ButtonGadget(#Btn_Connect, 155, 5, 75, 25, "Connect")
    ButtonGadget(#Btn_Quit, 235, 5, 60, 25, "Quit")
    StringGadget(#Str_Name, 55, 35, 95, 25, "")
    SetGadgetFont(#Str_Name, FontID(#Font_Win_0))
    ButtonGadget(#Btn_Name, 155, 35, 75, 25, "Change ")
    StringGadget(#Str_IP, 5, 5, 95, 25, "127.0.0.1")
    SetGadgetFont(#Str_IP, FontID(#Font_Win_0))
    StringGadget(#Str_Port, 105, 5, 40, 25, "6832", #PB_String_Numeric)
    SetGadgetFont(#Str_Port, FontID(#Font_Win_0))
    TextGadget(#Txt_Alias, 10, 40, 40, 20, "Alias")
    SetGadgetFont(#Txt_Alias, FontID(#Font_Win_0))
    DisableGadget(#Txt, 1)
EndProcedure

Procedure ResizeGadgetsWin()
    Protected FormWindowWidth, FormWindowHeight
    FormWindowWidth = WindowWidth(#Win)
    FormWindowHeight = WindowHeight(#Win)
    ResizeGadget(#Dialog, 5, 65, FormWindowWidth - 10, FormWindowHeight - StatusBarHeight(0) - 97)
    ResizeGadget(#Txt, 5, FormWindowHeight - 53, FormWindowWidth - 85, 25)
    ResizeGadget(#Btn_Send, FormWindowWidth - 75, FormWindowHeight - 53, 70, 25)
    ResizeGadget(#Btn_Connect, FormWindowWidth - 145, 5, 75, 25)
    ResizeGadget(#Btn_Quit, FormWindowWidth - 65, 5, 60, 25)
    ResizeGadget(#Btn_Name, 155, FormWindowHeight - 465, FormWindowWidth - 225, 25)
EndProcedure

; ------------------------- /form

Enumeration FormWindow
    #Refresh    
EndEnumeration

OpenWin() 
AddKeyboardShortcut(#Win, #PB_Shortcut_Return, 13)
AddWindowTimer(#Win, #Refresh, 1000)

Global Name$ = LSet("ID_" + Str(Random(99, 1)), 8, " ")
SetGadgetText(#Str_Name, Name$)

If InitNetwork() = 0
    AddGadgetItem(#Dialog, -1, "Error - Can't initialize the network !") 
Else
    AddGadgetItem(#Dialog, -1, "Network Ready.")
    AddGadgetItem(#Dialog, -1, "Click [Connect]")
EndIf

Global IP$ = "127.0.0.1"
Global Port = 6832
Global ID_Cnx
Global *Buffer = AllocateMemory(1000)


Declare Disconnect()

Procedure Connect()
    IP$     = GetGadgetText(#Str_IP)
    Port    = Val(GetGadgetText(#Str_Port))
    ; Bug: si pas de serveur actif
    If GetGadgetText(#Btn_Connect) = "Disconnect"
        Disconnect()
        ProcedureReturn 
    EndIf
    ID_Cnx = OpenNetworkConnection(IP$, Port)
    If ID_Cnx
        AddGadgetItem(#Dialog, -1, "Connect to " + IP$) 
        AddGadgetItem(#Dialog, -1, "ID connection " + Str(ID_Cnx)) 
        StatusBarText(0, 0, "Connected to " + IP$ + ":" + Port) 
        StatusBarText(0, 0, "Port: " + Str(Port))
        DisableGadget(#Txt, 0)
        DisableGadget(#Btn_Send, 0)
        SetGadgetText(#Btn_Connect, "Disconnect")
        Name$ = RSet(GetGadgetText(#Str_Name), 8, " ")
        SendNetworkString(ID_Cnx, "/New " + Name$, #PB_UTF8)
    Else
        AddGadgetItem(#Dialog, -1, "Can't connect to Server") 
        MessageRequester("Error", "Can't connect to Server", #PB_MessageRequester_Error) : End
    EndIf
EndProcedure

Procedure Disconnect()
    AddGadgetItem(#Dialog, -1, "End of Connection")
    ;CloseNetworkServer(0)
    If ID_Cnx = 0 : ProcedureReturn : EndIf
    SendNetworkString(ID_Cnx, "EOT " + Name$, #PB_UTF8)
    CloseNetworkConnection(ID_Cnx)
    StatusBarText(0, 0, "Disconnected From " + IP$) ;   
    DisableGadget(#Btn_Send, 1)
    Name$ = "ID_" + Str(Random(99, 1))
    SetGadgetText(#Btn_Connect, "Connecter")
EndProcedure


Procedure Send_Txt()
    TxtToSend$ = Name$ + " | " + GetGadgetText(#txt)
    Nb = SendNetworkString(ID_Cnx, TxtToSend$, #PB_UTF8)
    TxtToSend$ = ""
    SetGadgetText(#txt, "")
EndProcedure

Procedure Change_Name()
    Protected Old_Name$ = Name$
    Name$ = LSet(GetGadgetText(#Str_Name), 8, " ")
    AddGadgetItem(#Dialog, -1, Old_Name$ + " is now named: " + Name$)
    SendNetworkString(ID_Cnx, "/Change " + Name$, #PB_UTF8)
EndProcedure

; Connect()

Repeat 
    Win_Event = WaitWindowEvent()
    
    ; Events WINDOWS
    Select Win_Event
        Case #PB_Event_CloseWindow
            End
            
        Case #PB_Event_Menu
            If EventMenu() = 13
                Send_Txt()          
            EndIf
            
        Case #PB_Event_SizeWindow
            ResizeGadgetsWin()
            
        Case #PB_Event_Timer
            If EventTimer() = #Refresh
                While WindowEvent() : Wend
            EndIf
            
        Case #PB_Event_Gadget
            Select EventGadget()   
                    
                Case #Btn_Connect
                    Connect()  
                    
                Case #Btn_Quit
                    Disconnect()
                    End
                    
                Case #Btn_Send
                    If ID_Cnx
                        Send_Txt()
                    Else
                        AddGadgetItem(#Dialog, -1, "Connection Lost")
                    EndIf
                    
                Case #Btn_Name
                    Change_Name()
                    
            EndSelect
    EndSelect ; (Win_Event)
    
    ; info Events RESEAU
    If GetGadgetText(#Btn_Connect) = "Disconnect"
        Net_Event = NetworkClientEvent(ID_Cnx) 
    EndIf
    
    Select Net_Event
            
        Case #PB_NetworkEvent_Data
            ;While WindowEvent() : Wend
            FillMemory(*Buffer, 1000)
            ReceiveNetworkData(ID_Cnx, *Buffer, 1000)
            Received_Txt$ = PeekS(*Buffer, -1, #PB_UTF8)
            AddGadgetItem(#Dialog, -1, LTrim(Received_Txt$))
            Received_Txt$ = ""
            
    EndSelect
    
Until Quit = 1  

AddGadgetItem(#Dialog, -1, "End of Connection")
CloseNetworkConnection(ID_Client)
End

Global_Error:
MessageRequester("Error", ErrorMessage(), 16)
Je manipule assez mal la gestion directe de la mémoire (Peeks et autres, vidage des zones mémoire) si des spécialistes peuvent vérifier/améliore/fiabiliser ça: welcome.

Enjoy 8)