GolangWebDev
GolangWebDev
2540 0 0

Golang gracefully stop a tcp server

To gracefully stop a TCP server in Go, you can follow these steps:

Create a channel that will be used to signal the server to stop. For example:

stopChan := make(chan struct{})

Modify the server loop to check the stop channel before accepting new connections. For example:

for {
    select {
    case <-stopChan:
        fmt.Println("Stopping server")
        return
    default:
        conn, err := listener.Accept()
        if err != nil {
            fmt.Println(err)
            continue
        }
        go handleConnection(conn)
    }
}

To stop the server, send a value to the stop channel. For example:

stopChan <- struct{}{}

This will cause the server loop to exit, allowing the server to shut down gracefully.

Note that this is just one way to stop a TCP server in Go. Depending on your specific requirements, you may need to implement a different approach.

Use context

Here is an example of how you can use context to gracefully stop a TCP server:

package main

import (
	"context"
	"fmt"
	"net"
	"time"
)

func main() {
	// Create a context with a timeout of 5 seconds
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel() // Ensure the context is cancelled when we are done

	// Start the server
	ln, err := net.Listen("tcp", ":8080")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer ln.Close()

	// Accept connections in a loop
	for {
		// Check if the context is done
		select {
		case <-ctx.Done():
			fmt.Println("Stopping the server")
			return
		default:
			conn, err := ln.Accept()
			if err != nil {
				fmt.Println(err)
				return
			}
			go handleConnection(conn)
		}
	}
}

func handleConnection(conn net.Conn) {
	// Do something with the connection
	// ...
	conn.Close()
}

In this example, the server will stop accepting new connections and close all existing connections after 5 seconds. If you want to stop the server immediately, you can use context.WithCancel instead of context.WithTimeout and call the cancel function whenever you want to stop the server.

Also create a local context for each conn:

package main

import (
	"context"
	"io"
	"log"
	"net"
	"os"
	"os/signal"
	"syscall"
	"time"
)

func main() {
	ctx, cancel := context.WithCancel(context.Background())
	go func(ctx context.Context) {
		listener, err := net.Listen("tcp", "0.0.0.0:8000")
		if err != nil {
			log.Fatalln("can't listen")
		}
		for {
			select {
			case <-ctx.Done():
				listener.Close()
				log.Println("listener closed")
				return
			default:
				conn, err := listener.Accept()
				if err != nil {
					log.Println(err.Error())
				}
				go handle(ctx, conn)
			}
		}
	}(ctx)
	sigs := make(chan os.Signal, 1)
	signal.Notify(sigs, syscall.SIGUSR1, syscall.SIGUSR2)
	select {
	case <-sigs:
		cancel()
	}
	log.Println("signal received")
	time.Sleep(10 * time.Minute)
}

func handle(ctx context.Context, conn net.Conn) error {
	// create a local context which is canceled when the function returns
	ctx, cancel := context.WithCancel(ctx)
	defer cancel()
	// close the connection when the context is canceled
	go func() {
		<-ctx.Done()
		conn.Close()
	}()
	// use the connection
	_, err := io.Copy(os.Stdout(), conn)
	return err
}
0

See Also


Discussion

Login Topics