En esta clase, abordamos la creación de un servidor de chat utilizando Go. Si bien en la lección anterior creamos el cliente, ahora es momento de profundizar en el backend del proyecto para dar vida a nuestro sistema de mensajería. Vamos a explorar el código y entender cada pieza fundamental en este rompecabezas.
¿Qué es el tipo client y cómo se utiliza?
Primero, definimos un nuevo tipo llamado client, que es esencialmente un canal que transmite strings. Este tipo es clave, ya que es el medio por el cual enviaremos mensajes dentro del chat. Aquí están los pasos necesarios:
Definición inicial:
type client chan<-string
Variables de canal:
incomeingClients: canal para los clientes que se conectan.
livingClients: canal para los que abandonan el chat.
messages: canal para los mensajes en sí, de tipo string.
¿Cómo se gestionan las conexiones del cliente?
La función handleConnection se encarga de manejar las conexiones de los clientes de manera individual. Cada cliente que se conecta es asignado a una instancia de esta función, asegurando un manejo efectivo y seguro de los recursos.
Pasos dentro de handleConnection:
Asignar un nombre único a cada cliente usando la dirección remota.
clientName := con.RemoteAddr().String()
Enviar un mensaje de bienvenida al cliente que se conecta y notificar al resto de los clientes.
messages <- fmt.Sprintf("Bienvenido al servidor, %s", clientName)messages <- fmt.Sprintf("Nuevo cliente ha llegado: %s", clientName)
Lectura de mensajes: Utilizando un escáner para leer continuamente mensajes desde la terminal:
La función messageWrite es responsable de escribir los mensajes a través de la conexión de cada cliente. Utiliza una goroutine para manejar la concurrencia y mantener el flujo de mensajes constante.
Cuando un cliente decide desconectar, es importante informar a los demás y liberar recursos:
Se finaliza el ciclo de escaneo de mensajes.
Se reporta que un cliente ha abandonado el chat.
messages <- fmt.Sprintf("%s ha dejado el chat.", clientName)
¿Cuáles son las herramientas clave utilizadas?
Para llevar a cabo este proyecto, hemos aprovechado las siguientes herramientas de Go:
Channels: Para la comunicación entre goroutines.
Goroutines: Para la ejecución concurrente de las funciones.
Packages estándar de Go: Como net para manejar las conexiones y fmt para el formateo de salida.
Con este conjunto de herramientas y técnicas, has aprendido a establecer la base de un servidor de chat en Go. Aunque este es solo el comienzo, invita a la exploración y manipulación de conexiones concurrentes y mensajes en un entorno de producción real. Si estás interesado en completar y ejecutar este proyecto, te animo a continuar aprendiendo y descubrir cómo optimizar y expandir este sistema de chat. ¡Buena suerte y sigue adelante!
Personalmente se hace difícil seguir el código cuando se utilizan nombres de variables que se pueden confundir fácilmente, no es la primera vez (recuerdo una clase en que los nombres de las variables estaban cruzados con los structs de referencia).
.
Por ejemplo, en lugar de utilizar "message" (mensajes para el cliente) y "messages" (mensajes del chat), los cuales claramente se confunden, se pueden utilizar nombres como "clientMessages" para los mensajes del cliente y "chatMessages" para los mensajes del chat.
.
Considero que no solamente es importante enseñar a desarrollar, sino también enseñar buenas prácticas y hábitos. Además que en este caso el disponer de variables claras hace que sea más sencillo comprender todo lo que se está realizando, más cuando es algo complejo (mejor complejo que complicado).
Concuerdo totalmente, por suerte lei tu comentario antes de empezar el video y aplique esos nombres para las variables y se hizo más claro leer lo que estaba haciendo.
De la otra forma es ilegible
Néstor, deberían rehacer este video, ya que es muy confuso la forma en que usas tanto la variable message, que uno se confunde y no entiende de donde pertenece
El código de la clase no compila porque host y port están definidos ambos en el mismo package main.
Si, y la función main también está duplicada pero calculo lo va a solucionar en clases subsiguientes. Este es el problema de escribir todo el código sin ir probándolo. Está escribiendo todo el programa de un tirón, sin hacer ni una prueba
Nadie programa de esta manera, uno va escribiendo y probando el código a medida que lo va escribiendo, si pudiéramos escribir todo este tipo de proyectos si no se va probando para ir entendiendo cada pieza :(
package main
import("bufio""flag""fmt""net")type Client chan<- string
var( entering =make(chan Client) leaving =make(chan Client) messages =make(chan string))var( host = flag.String("h","localhost","hostname") port = flag.String("p","3090","port"))// Client1 -> Server -> HanldeConnection(Client1)// HanldeConnnection handles the client connection of a single userfunc HanldeConnection(conn net.Conn){ defer conn.Close()// Create the client channelmessage:=make(chan string) go MessageWrite(conn, message)// Get the client's nameclientName:= conn.RemoteAddr().String()// Send just to the client his name message <-"Welcome to the server, your name is "+ clientName
// Send the message to all the clients messages <- clientName +" has joined!"// Add the client to the list of clients entering <- message
// Read the messages from the client// If the loop breaks, that means that the client has disconnectedinputMessage:= bufio.NewScanner(conn)for inputMessage.Scan(){ messages <- clientName +": "+ inputMessage.Text()}// Remove the client from the list of clients leaving <- message
messages <- clientName +" has left!"}// MessageWrite recives messages from the channel and writes them to the clientfunc MessageWrite(conn net.Conn, messages <-chan string){formsg:= range messages { fmt.Fprintln(conn, msg)}}
🤯🤯
me encanta como explica el profe, pero esta clase en particular me parece que no tiene sentido, es un monton de garabatos en Go que ni idea si anda, si la idea era plasmar el concepto del chat, con algun UML o un grafico era suficiente. pero a nivel de codigo no se entiende, no se si en Go esta es la mejor practica, no me sumo esta clase, me resto.
sin en lugar de la dirección del host (address) se maneja el nombre del host (hostname) de alguna forma?
¿Puedes rehacer tu pregunta? xD Lo siento pero no es muy clara. ¿Te refieres a que si se puede utilizar el hostname en lugar de la ip a la hora de configurar la conexión TCP?