Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
140 lines (118 sloc) 6.01 KB
\epi{"Good communication is as stimulating as black coffee, and just as hard
to sleep after."}{\textsc{ANNE MORROW LINDBERGH}}
\noindent{}In this chapter we are going to look at the building blocks in Go for
communicating with the outside world.
Reading from (and writing to) files is easy in Go. This program
only uses the \package{os} package to read data from the file \file{/etc/passwd}.
\lstinputlisting[caption=Reading from a file (unbufferd),label=src:read]{src/file.go}
If you want to use \first{buffered}{buffered} IO there is the
\package{bufio}\index{package!bufio} package:
\lstinputlisting[caption=Reading from a file (bufferd),label=src:bufread]{src/buffile.go}
\subsection{Line by line}
The previous program reads a file in its entirely, but a more common scenario is that
you want to read a file on a line-by-line basis. The following snippet show a way
to do just that:
f, _ := os.Open("/etc/passwd", os.O_RDONLY, 0666)
r := bufio.NewReader(f)
for {
s, ok := r.ReadString('\n'); true { |\coderemark{Read a line from the input}|
// ... \coderemark{\var{s} holds the string, with the \package{string} package you can parse it}
A more robust method (but slightly more complicated) is \func{ReadLine}, see the documentation
of the \package{bufio} package.
\section{Command line arguments}
\label{sec:option parsing}
Arguments from the command line are available inside your program via
the string slice \var{os.Args}, provided you have imported the package
\package{os}. The \package{flag} package has a more sophisticated
interface, and also provides a way to parse flags. Take this example
from a little DNS query tool:
var dnssec *bool = flag.Bool("dnssec", false, "Request DNSSEC records") |\longremark{Define a \texttt{bool} flag, %%
\texttt{-dnssec}. The variable must be a pointer otherwise the package can not set its value;}|
var port *string = flag.String("port", "53", "Set the query port") |\longremark{Idem, but for a \texttt{port} option;}|
flag.Usage = func() { |\longremark{Slightly redefine the \func{Usage} function, to be a little more verbose;}|
fmt.Fprintf(os.Stderr, "Usage: %s [@server] [qtype] [qclass] [name ...]\n", os.Args[0])
flag.PrintDefaults() |\longremark{For every flag given, \func{PrintDefaults} will output the help string;}|
flag.Parse() |\longremark{Parse the flags and fill the variables.}|
\section{Executing commands}
The \package{exec}\index{package!exec} package has function to run external commands, and it the premier way to
execute commands from within a Go program. We start commands with
the \func{Run} function:
func Run(argv0 string, argv, envv []string, dir string, stdin, stdout, stderr int) (p *Cmd, err os.Error)
Run starts the binary prog running with
arguments \var{argv} and environment \var{envv}.
It returns a pointer to a new \type{Cmd} representing the command or an error.
Lets execute \verb|ls -l|:
import "exec"
cmd, err := exec.Run("/bin/ls", []string{"ls", "-l"}, nil, "", exec.DevNull, exec.DevNull, exec.DevNull)
In the \package{os}\index{package!os} package we find the \func{StartProcess} function. This
is another way (but more low level) to start executables.\footnote{There is talk on
the go-nuts mailing list about separating \func{Fork} and
The prototype for \func{StartProcess} is:
func StartProcess(name string, argv []string, envv []string, dir string, fd []*File) (pid int, err Error)
With the following documentation:
\func{StartProcess} starts a new process with the program, arguments,
and environment specified by \var{name}, \var{argv}, and \var{envv}. The \var{fd} array specifies the
file descriptors to be set up in the new process: \var{fd[0]} will be Unix file
descriptor 0 (standard input), \var{fd[1]} descriptor 1, and so on. A \type{nil} entry
will cause the child to have no open file descriptor with that index.
If \var{dir} is not empty, the child chdirs into the directory before execing the program.
Suppose we want to execute \verb|ls -l| again:
import "os"
pid, err := os.StartProcess("/bin/ls", []string{"ls", "-l"}, nil, "", []*os.File{ os.Stdin, os.Stdout, os.Stderr})
defer os.Wait(pid, os.WNOHANG) |\coderemark{Otherwise you create a zombie}|
Note that \lstinline{os.Wait} (among other things) returns the
\func{exit code}, with:
w := os.Wait(pid, os.WNOHANG)
e := w.WaitStatus.ExitStatus() |\coderemark{ExitStatus() returns an integer}|
All network related types and functions can be found in the package \package{net}. One of the
most important functions in there is \func{Dial}\index{networking!Dial}. When you \func{Dial}
into a remote system the function returns a \var{Conn} interface type, which can be used
to send and receive information. The function \func{Dial} neatly abstracts away the network
family and transport. So IPv4 or IPv6, TCP or UDP can all share a common interface.
Dialing a remote system (port 80) over TCP, then UDP and lastly TCP over IPv6 looks
like this:\footnote{In case
you are wondering, and 2620:0:2d0:200::10 are \url{}.}
conn, err := Dial("tcp", "", "")
conn, err := Dial("udp", "", "")
conn, err := Dial("tcp", "", "[2620:0:2d0:200::10]:80") |\coderemark{Brackets are mandatory}|
And with \var{conn} you can do read/write \todo{dkls}.
\todo{Write echo server}
\section{Netchan: networking and channels}