Go has the type Addr
to represent a network and address:port pair:
type Addr interface {
Network() string // name of the network (for example, "tcp", "udp")
String() string // string form of address (for example, "192.0.2.1:25", "[2001:db8::1]:80")
}
We won't be using this.
In many cases, Go uses a string "host:port" to represent a socket address.
The function JoinHostPort(host, port string) string
can
construct such an address. Not a big deal, except for the special case
when the host is an IPv6 address (contains a ':'): then it encloses
the address in '[...]' as in
JoinHostPort("::1",, 80) => "[::1]:80"
.
The function net.Dial(network, address string) (Conn, error)
connects to the address using the given network protocol.
This is a general purpose function, and the network protocols include
"tcp4" (IPv4-only), "tcp6" (IPv6-only), "udp", "udp4" (IPv4-only),
"udp6" (IPv6-only), "ip", "ip4" (IPv4-only), "ip6" (IPv6-only),
"unix", "unixgram" and "unixpacket". For TCP, we use "tcp".
As with the Java example, we will read lines from stdin.
The simplest method to read a line
is by the function Reader.ReadString('\n')
.
The function returns a string including the terminator.
For POSIX systems the line will end in '\n', but for Windows
it will end in "\r\n". To test against the "BYE" string
we will need to compare the line minus the end of line
character(s).
The property runtime.GOOS
can be used to distinguish
between POSIX and Windows.
Reading and writing strings can be done using the bufio
package of Reader
and Writer
.
After a write, we also to flush the string to ensure it is written.
Like with Java, the conversion to and from bytes will be discussed
later.
The client which sends lines to the server and reads them back is EchoClient.go:
/* EchoClient
*/
package main
import (
"fmt"
"net"
"os"
"runtime"
"bufio"
)
func main() {
if len(os.Args) != 2 {
fmt.Fprint(os.Stderr, "Usage: ", os.Args[0], " host\n")
os.Exit(1)
}
service := os.Args[1] + ":2000"
conn, err := net.Dial("tcp", service)
checkError("Dial", err)
fmt.Println("Connected")
console := bufio.NewReader(os.Stdin)
reader := bufio.NewReader(conn)
writer := bufio.NewWriter(conn)
eol_len := 1 // POSIX: \n
if runtime.GOOS == "windows" {
eol_len = 2 // Windows: \r\n
}
for {
fmt.Print("Enter line:")
line, _ := console.ReadString('\n')
fmt.Println("Line read: '" + line + "'")
if line[:len(line) - eol_len] == "BYE" {
break
}
_, err = writer.WriteString(line)
writer.Flush()
checkError("Write", err)
str, err := reader.ReadString('\n')
checkError("Read", err)
fmt.Println("Echoed: '" + str + "'")
}
os.Exit(0)
}
func checkError(errStr string, err error) {
if err != nil {
fmt.Fprint(os.Stderr, errStr, err.Error())
os.Exit(1)
}
}
Run by
go run EchoClient localhost
A server finds a TCP address corresponding to a port using
net.ResolveTCPAddr()
which takes two arguments:
a network type, here "tcp" and a TCP address, here of anyhost
plus port ":2000". The server then listens on that address,
and will Accept()
a connection.
Reads and writes are the done on that connection
using the Read()
and Write()
functions.
The server will accept connections both form IPv4 and IPv6 clients. It is multi-threaded, running each connection in a coroutine. It is EchoServer.go:
/* SimpleEchoServer
*/
package main
import (
"fmt"
"net"
"os"
)
func main() {
service := ":2000"
tcpAddr, err := net.ResolveTCPAddr("tcp", service)
checkError(err)
listener, err := net.ListenTCP("tcp", tcpAddr)
checkError(err)
for {
conn, err := listener.Accept()
if err != nil {
continue
}
fmt.Println("Connected")
// run as a coroutine
go handleClient(conn)
}
}
func handleClient(conn net.Conn) {
// close connection on exit
defer conn.Close()
var data []byte
data = make([]byte, 2048, 2048)
for {
n, err := conn.Read(data)
if err != nil {
fmt.Println("Disconnecting")
return
}
_, err = conn.Write(data[0:n])
if err != nil {
return
}
}
}
func checkError(err error) {
if err != nil {
fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
os.Exit(1)
}
}
Copyright © Jan Newmarch, jan@newmarch.name
" Network Programming using Java, Go, Python, Rust, JavaScript and Julia"
by
Jan Newmarch
is licensed under a
Creative Commons Attribution-ShareAlike 4.0 International License
.
Based on a work at
https://jan.newmarch.name/NetworkProgramming/
.