Learn how to write TCP servers using Go's net package
TCP is a widely used network protocol. It's the underlying protocol for HTTP, SSH and many other protocols that you're probably familiar with.
In this concept we'll learn how to write a TCP server in Go using the net
package.
Not familiar with TCP? Try the "TCP: An Overview" concept first.
TCP is a widely used network protocol. It's the underlying protocol for HTTP, SSH and many other protocols that you're probably familiar with.
In this concept we'll learn how to write a TCP server in Go using the net
package.
Not familiar with TCP? Try the "TCP: An Overview" concept first.
net
packageGo's net
package provides access to networking primitives.
To write TCP servers in Go, you'll need to be familiar with the following functions:
We'll start by looking at net.Dial
and net.Listen
.
net.Dial
is used to initiate outbound connections.
Example usage:
// Connects to a TCP server on localhost:8080
conn, err := net.Dial("tcp", "localhost:8080")
net.Listen
is used to create servers to accept inbound connections.
Example usage:
// Starts a TCP server listening on localhost:8080
l, err := net.Listen("tcp", "localhost:8080")
net.Listen
functionThis is the interface for net.Listen
:
func Listen(network string, address string) (Listener, error)
To create a TCP server, you'd specify "tcp" as network
, and a string like "localhost:8080" as the address
:
// Starts a TCP server listening on localhost:8080
l, err := net.Listen("tcp", "localhost:8080")
net.Listener
interfacenet.Listener
is the interface returned from net.Listen
.
listener, err := net.Listen("tcp", "localhost:8080")
Here are the functions inside it:
type Listener interface {
// Accept waits for and returns the next connection to the listener.
Accept() (Conn, error)
// Close closes the listener.
// Any blocked Accept operations will be unblocked and return errors.
Close() error
// Addr returns the listener's network address.
Addr() Addr
}
Once you've created a listener, you can use net.Listener#Accept()
to wait for a client to connect.
This function blocks if no clients have connected to the server yet.
// Block until we receive an incoming connection
conn, err := listener.Accept()
if err != nil {
return err
}
net.Conn
interfacenet.Conn
is the interface returned from net.Listener#Accept()
.
The important functions in this interface are:
type Conn interface {
// Read reads data from the connection.
Read(b []byte) (n int, err error)
// Write writes data to the connection.
Write(b []byte) (n int, err error)
// Close closes the connection.
// Any blocked Read or Write operations will be unblocked and return errors.
Close() error
}
You can use conn.Read()
and conn.Write()
to read and write from a connection.
To read data from a connection, you'll need to pass in a byte slice to conn.Read
. The data received will be stored in this byte slice. conn.Read
returns the number of bytes read:
buf := make([]byte, 1024)
n, err := conn.Read(buf)
fmt.Printf("received %d bytes", n)
fmt.Printf("received the following data: %s", string(buf[:n]))
To write data to a TCP connection, you'll need to pass in a byte slice to conn.Write
. It returns the number of bytes written:
message := []byte("Hello, server!")
n, err := conn.Write(message)
fmt.Printf("sent %d bytes", n)
Now that you're familiar with net.Listen, net.Listener and net.Conn, let's see how to put them all together to create a simple TCP server that echos all input it receives:
package main
import (
"fmt"
"net"
)
func main() {
// Listen for incoming connections
listener, err := net.Listen("tcp", "localhost:8080")
if err != nil {
fmt.Println("Error:", err)
return
}
// Ensure we teardown the server when the program exits
defer listener.Close()
fmt.Println("Server is listening on port 8080")
for {
// Block until we receive an incoming connection
conn, err := listener.Accept()
if err != nil {
fmt.Println("Error:", err)
continue
}
// Handle client connection
handleClient(conn)
}
}
func handleClient(conn net.Conn) {
// Ensure we close the connection after we're done
defer conn.Close()
// Read data
buf := make([]byte, 1024)
n, err := conn.Read(buf)
if err != nil {
return
}
fmt.Println("Received data", buf[:n])
// Write the same data back
conn.Write(buf[:n])
}
You've now learnt about how to use functions in the net
package to build a TCP server.
A quick recap of the functions and interfaces we covered:
net.Listen
: Returns a net.Listener
instancenet.Listener#Accept
: Blocks until a client connects, returns a net.Conn
instancenet.Conn#Read
: Reads data from a connectionnet.Conn#Write
: Writes data to a connectionThe full documentation for the net
package can be found here.