Skip to main content
The net package provides the tools you need to easily build TCP socket servers in Go. This example demonstrates how to create a server that accepts connections and handles them concurrently.

Complete TCP Server Example

package main

import (
	"bufio"
	"fmt"
	"log"
	"net"
	"strings"
)

func main() {
	// `net.Listen` starts the server on the given network
	// (TCP) and address (port 8090 on all interfaces).
	listener, err := net.Listen("tcp", ":8090")
	if err != nil {
		log.Fatal("Error listening:", err)
	}

	// Close the listener to free the port
	// when the application exits.
	defer listener.Close()

	// Loop indefinitely to accept new client connections.
	for {
		// Wait for a connection.
		conn, err := listener.Accept()
		if err != nil {
			log.Println("Error accepting conn:", err)
			continue
		}

		// We use a goroutine here to handle the connection
		// so that the main loop can continue accepting more
		// connections.
		go handleConnection(conn)
	}
}

// `handleConnection` handles a single client connection,
// reading one line of text from the client and returning a response.
func handleConnection(conn net.Conn) {
	// Closing the connection releases resources when
	// we are finished interacting with the client.
	defer conn.Close()

	// Use `bufio.NewReader` to read one line of data
	// from the client (terminated by a newline).
	reader := bufio.NewReader(conn)
	message, err := reader.ReadString('\n')
	if err != nil {
		log.Printf("Read error: %v", err)
		return
	}

	// Create and send a response back to the client,
	// demonstrating two-way communication.
	ackMsg := strings.ToUpper(strings.TrimSpace(message))
	response := fmt.Sprintf("ACK: %s\n", ackMsg)
	_, err = conn.Write([]byte(response))
	if err != nil {
		log.Printf("Server write error: %v", err)
	}
}

Key Components

1

Create Listener

net.Listen("tcp", ":8090") creates a TCP listener on port 8090. This binds to all network interfaces on the machine.
2

Accept Connections

listener.Accept() blocks until a client connects, then returns a net.Conn object representing the connection.
3

Handle Concurrently

Each connection is handled in a separate goroutine with go handleConnection(conn), allowing the server to handle multiple clients simultaneously.
4

Read and Write

Use standard I/O operations on the net.Conn to communicate with the client. Always close connections when finished.

Concurrent Connection Handling

The server uses goroutines to handle each connection concurrently. This means the server can accept and process multiple client connections at the same time without blocking.
go handleConnection(conn)
This pattern is essential for building scalable network servers that can handle many simultaneous connections.

Resource Management

Proper resource cleanup is critical in network programming:
defer listener.Close()
Ensures the listening socket is closed when the program exits, freeing the port.
defer conn.Close()
Each connection must be closed after handling to prevent resource leaks.

Running the Example

# Run the TCP server in the background.
$ go run tcp-server.go &

# Send data and capture the response using netcat.
$ echo "Hello from netcat" | nc localhost 8090
ACK: HELLO FROM NETCAT
You can test the server with any TCP client like netcat (nc), telnet, or a custom Go client.

Next Steps

HTTP Server

Build higher-level HTTP servers

Context

Learn about context for cancellation

Build docs developers (and LLMs) love