Jorge Fuertes

Consultor de sistemas infomáticos.
Administración de sistemas, desarrollo.

Mi primer programa en Go

300px-Ken_n_dennis

Me he decidido a probar esta cosa del “Go”, o “go-lang” de Google, al ver en la Wikipedia que uno de los que diseñaron el lenguaje es Ken Thompson.

El nombre es desafortunado, resulta difícil encontrar recursos en Internet al ser demasiado genérico, pero bueno, si vamos buscando por “golang” y “go-lang” la cosa mejora un poco.

He hecho un pequeño servidor concurrente que, cuando nos conectamos admite dos comandos: ping y end. Al primero responde con pong y al segundo con una despedida y una desconexión.

Hasta ahí nada impresionante, aunque lo bueno empieza cuando vemos el código, menos de sesenta líneas y porque lo he adornado pillando el hostname para probar más cosas, y, aquí lo bueno de verdad, es plenamente concurrente, podemos abrirle todas las conexiones que queramos que el tío va lanzando procesos internos hasta que se quemen los recursos (evidentemente habría que establecer límites y controles en un servidor de verdad).

Sin más os dejo el código por si tenéis curiosidad:


/*
 * Small ping-telnet server example
 * @2014 Jorge Fuertes - http://jorgefuertes.com
 *
 * Licensed under GPL v3: http://www.gnu.org/licenses/gpl-3.0.txt
 */

package main

import (
	"net"
	"net/textproto"
	"log"
	"os/exec"
	"fmt"
	"bufio"
)

func main() {
	fmt.Printf("My hostname: %s", getMyHostname())
	ln, err := net.Listen("tcp", ":8082")
	if err != nil {
		log.Fatal("ERROR: ", err)
	} else {
		log.Print("Listening on port 8082")
		for {
			conn, err := ln.Accept()
			if err != nil {
				log.Fatal("ERROR: ", err)
				continue
			}
			go handleConnection(conn)
		}
	}
}

func handleConnection(conn net.Conn) {
	log.Print("New connection!")
	reader  := bufio.NewReader(conn)
	tpRead  := textproto.NewReader(reader)
	writer  := bufio.NewWriter(conn)
	tpWrite := textproto.NewWriter(writer)
	tpWrite.PrintfLine("Hello from %s", getMyHostname())
	tpWrite.PrintfLine("Commands: ping, end.")
	for {
		line, _ := tpRead.ReadLine()
		log.Print("RECV: ", line)
		if (line == "ping") {
			log.Print("SEND: pong")
			tpWrite.PrintfLine("pong")
		} else if (line == "end") {
			log.Print("RECV: end")
			tpWrite.PrintfLine("OK, bye!")
			break
		}
	}
	conn.Close()
}

func getMyHostname() ([]byte) {
	hostnameCmd, _ := exec.LookPath("hostname")
	hostname, _ := exec.Command(hostnameCmd).Output()
	return hostname
}

Si queréis ejecutarlo, con Go instalado:

go run fichero.go

Y para compilar a ejecutable:

go build fichero.go

Estoy entusiasmado con este lenguaje.