forked from miekg/gobook
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgo-communication.tex
158 lines (134 loc) · 6.38 KB
/
go-communication.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
\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.
\section{Files and directories}
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}
\showremarks
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}
\showremarks
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:
\begin{lstlisting}
f, _ := os.Open("/etc/passwd")
defer f.Close()
r := bufio.NewReader(f)
s, ok := r.ReadString('\n') |\coderemark{Read a line from the input}|
// ... \coderemark{\var{s} holds the string, with the \package{strings} package you can parse it}
\end{lstlisting}
A more robust method (but slightly more complicated) is \func{ReadLine}, see the documentation
of the \package{bufio} package.
A common scenario in shell scripting is that you want to check if a directory
exists and if not, create one.
\begin{minipage}{.5\textwidth}
\begin{lstlisting}[language=sh,caption={Create a directory in the shell}]
if [ ! -e name ]; then
mkdir name
else
# error
fi
\end{lstlisting}
\end{minipage}
\hspace{1em}
\begin{minipage}{.5\textwidth}
\begin{lstlisting}[caption={Create a directory with Go}]
if f, e := os.Stat("name"); e != nil {
os.Mkdir("name", 0755)
} else {
// error
}
\end{lstlisting}
\end{minipage}
\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 DNS query tool:
\begin{lstlisting}
dnssec := 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;}|
port := 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 [OPTIONS] [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.}|
\end{lstlisting}
\showremarks
\section{Executing commands}
The \package{exec}\index{package!exec} package has functions to run external commands, and it the premier way to
execute commands from within a Go program. It works by defining a \var{*exec.Cmd} structure for which it
defines a number of methods.
Lets execute \verb|ls -l|:
\begin{lstlisting}
import "exec"
cmd := exec.Command("/bin/ls", "-l") |\coderemark{Create a \var{*cmd}}|
err := cmd.Run() |\coderemark{\func{Run()} it}|
\end{lstlisting}
Capturing standard output from a command is also easy to do:
\begin{lstlisting}
import "exec"
cmd := exec.Command("/bin/ls", "-l")
buf, err := cmd.Ouput() |\coderemark{\var{buf} is a (\type{[]byte})}|
\end{lstlisting}
\section{Networking}
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, 192.0.32.10 and 2620:0:2d0:200::10 are \url{www.example.org}.}
\begin{lstlisting}
conn, e := Dial("tcp", "192.0.32.10:80")
conn, e := Dial("udp", "192.0.32.10:80")
conn, e := Dial("tcp", "[2620:0:2d0:200::10]:80") |\coderemark{Mandatory brackets}|
\end{lstlisting}
If there were no errors (returned in \var{e}), you can use \var{conn} to read and write.
The primitives defined in the package \package{net} are:
\begin{quote}
// \func{Read} reads data from the connection.\\
// \func{Read} can be made to time out and return a \var{net.Error} with \lstinline{Timeout() == true}\\
// after a fixed time limit; see \func{SetTimeout} and \func{SetReadTimeout}.\\
\lstinline{Read(b []byte) (n int, err os.Error)}
\end{quote}
\begin{quote}
// \func{Write} writes data to the connection.\\
// \func{Write} can be made to time out and return a \var{net.Error} with \lstinline{Timeout() == true}\\
// after a fixed time limit; see \func{SetTimeout} and \func{SetWriteTimeout}.\\
\lstinline{Write(b []byte) (n int, err os.Error)}
\end{quote}
But these are the low level nooks and crannies\footnote{Exercise Q\ref{ex:echo} is about using
these.}, you will almost always use higher level packages.
Such as the \package{http} package. For instance a simple Get for http:
\begin{lstlisting}
package main
import ( "io/ioutil"; "http"; "fmt" ) |\longremark{The imports needed;}|
func main() {
r, err := http.Get("http://www.google.com/robots.txt") |\longremark{Use http's \func{Get} to retrieve the html;}|
if err != nil { fmt.Printf("%s\n", err.String()); return } |\longremark{Error handling;}|
b, err := ioutil.ReadAll(r.Body) |\longremark{Read the entire document into \var{b};}|
r.Body.Close()
if err == nil { fmt.Printf("%s", string(b)) } |\longremark{If everything was OK, print the document.}|
}
\end{lstlisting}
\showremarks
\section{Exercises}
\input{ex-communication/ex-processes.tex}
\input{ex-communication/ex-wordcount.tex}
\input{ex-communication/ex-uniq.tex}
\input{ex-communication/ex-quine.tex}
\input{ex-communication/ex-echo.tex}
\input{ex-communication/ex-numbercruncher.tex}
\input{ex-communication/ex-finger.tex}
\cleardoublepage
\section{Answers}
\shipoutAnswer