Freeing a port before running a server instant - go

I want to run a go server at linux based system, it happened in soe cases that i found the same port is busy with another app, so i want to kill the running process at that port, and run my server instead, so I wrote the below code:
func main() {
host := "127.0.0.1"
port := "8070"
server := http.Server{
Addr: "127.0.0.1:8070",
}
http.Handle("/www/", http.StripPrefix("/www/", http.FileServer(http.Dir("./www"))))
ln, err := net.Listen("tcp", ":"+port)
if err != nil {
fmt.Fprintf(os.Stderr, "Can't listen on port %q: %s \n", port, err)
// kill the running process at this port
_, err := exec.Command("fuser", "-k", "8070/tcp").Output()
if err != nil {
fmt.Printf("Failed to kill process at Port %q\n", port)
} else {
fmt.Printf("TCP Port %q is available\n", port)
server.ListenAndServe()
}
} else {
ln.Close()
server.ListenAndServe()
}
}
I was able to get the response TCP Port 8070 is available whihc means there was another running process and it had been killed, but my app is closed directly without running my server at the same port which had been already closed!
hajsf#AIS-DM-YOUSEF-L:~/myapp$ go run myapp
Can't listen on port "8070": listen tcp :8070: bind: address already in use
TCP Port "8070" is available
hajsf#AIS-DM-YOUSEF-L:~/myapp$
In the origional terminal (the old instance of the app0 I got;
hajsf#AIS-DM-YOUSEF-L:~/myapp$ go run myapp
signal: killed
hajsf#AIS-DM-YOUSEF-L:~/myapp$

As you can see in the response How to kill a process running on particular port in Linux?
Your command _, err := exec.Command("fuser", "-k", "8070/tcp").Output() kill the process but doesn't cleanup the resource ie: port listening.
The port is put into TIME_WAIT state after the parent process is killed.
And you need to wait some time your OS/Kernel cleanup the port/socket
A better alternative is to handle the kill sigint from fuser and do a graceful shutdown
package main
import (
"context"
"fmt"
"net"
"net/http"
"os"
"os/exec"
"os/signal"
"time"
)
func runServer(host, port string) {
server := http.Server{
Addr: host + ":" + port,
}
http.Handle("/www/", http.StripPrefix("/www/", http.FileServer(http.Dir("./www"))))
go func() {
if err := server.ListenAndServe(); err != nil {
}
}()
// Setting up signal capturing
stop := make(chan os.Signal, 1)
signal.Notify(stop, os.Interrupt)
// Waiting for SIGINT (kill -2)
<-stop
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := server.Shutdown(ctx); err != nil {
// handle err
}
}
func main() {
host := "127.0.0.1"
port := "8070"
ln, err := net.Listen("tcp", host+":"+port)
if err != nil {
fmt.Fprintf(os.Stderr, "Can't listen on port %q: %s \n", port, err)
// kill the running process at this port
cmd := exec.Command("fuser", "-k", "-2", "8070/tcp")
fmt.Println("wait")
err = cmd.Run()
if err != nil {
fmt.Printf("Failed to kill process at Port %q\n", port)
} else {
fmt.Printf("TCP Port %q is available\n", port)
runServer(host, port)
}
} else {
ln.Close()
runServer(host, port)
}
}

worked well on CentOS 7, but same issue with a Ubuntu server. #MoiioM 's answer is fine. But if another app is not the golang app itself, here is another way: set a SO_REUSEADDR flag on the socket
package main
import (
"context"
"fmt"
"net"
"net/http"
"os"
"os/exec"
"syscall"
"golang.org/x/sys/unix"
)
func reusePort(network, address string, conn syscall.RawConn) error {
return conn.Control(func(descriptor uintptr) {
syscall.SetsockoptInt(int(descriptor), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1)
})
}
func main() {
port := "8070"
server := http.Server{}
http.Handle("/www/", http.StripPrefix("/www/", http.FileServer(http.Dir("./www"))))
ln, err := net.Listen("tcp", ":"+port)
if err != nil {
fmt.Fprintf(os.Stderr, "Can't listen on port %q: %s \n", port, err)
// kill the running process at this port
_, err := exec.Command("fuser", "-k", "8070/tcp").Output()
if err != nil {
fmt.Printf("Failed to kill process at Port %q\n", port)
} else {
fmt.Printf("TCP Port %q is available\n", port)
config := &net.ListenConfig{Control: reusePort}
listener, err := config.Listen(context.Background(), "tcp", ":"+port)
if err != nil {
panic(err)
}
if err := server.Serve(listener); err != nil {
panic(err)
}
}
} else {
if err := server.Serve(ln); err != nil {
panic(err)
}
}
}

I was able to solve it with panic ... recover as below:
package main
import (
"fmt"
"net"
"net/http"
"onsen/resources"
"onsen/routes"
"os"
"os/exec"
)
func main() {
http.Handle("/webUI/", http.StripPrefix("/webUI/", http.FileServer(http.FS(resources.WebUI))))
http.Handle("/www/", http.StripPrefix("/www/", http.FileServer(http.Dir("./www"))))
for key, value := range routes.Urls() {
http.HandleFunc(key, value)
}
runServer()
}
func runServer() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered in f", r)
runServer()
}
}()
host := "127.0.0.1"
port := "8070"
server := http.Server{
Addr: fmt.Sprintf("%v:%v", host, port),
}
ln, err := net.Listen("tcp", ":"+port)
if err != nil {
fmt.Fprintf(os.Stderr, "Can't listen on port %q: %s \n", port, err)
// kill the running process at this port
_, err := exec.Command("fuser", "-k", "8070/tcp").Output()
if err != nil {
panic(fmt.Sprintf("Failed to kill process at Port %q\n", port))
} else {
fmt.Printf("TCP Port %q is available\n", port)
fmt.Println("server started...")
if err := server.Serve(ln); err != nil {
panic(err)
}
}
} else {
fmt.Println("server started...")
if err := server.Serve(ln); err != nil {
panic(err)
}
}
}
And got the output as below:

Related

golang simple server with interactive prompt

I am trying to build a simple CLI interface for my go process, I need to listen and serve on TCP port and get stats when connected to the port on TCP . I came across 'terminal' package to help with Password prompt, command history and other things. I tried to write up some code to achieve this. Although my client is not receiving any prompt or server is stuck on 'ReadLine' method. Any helpers?
package main
import (
"bufio"
"fmt"
"golang.org/x/crypto/ssh/terminal"
"io"
"net"
_ "time"
)
func handleConnection(conn net.Conn) error {
fmt.Println("Handling new connection...")
defer func() {
fmt.Println("Closing connection...")
conn.Close()
}()
r := bufio.NewReader(conn)
w := bufio.NewWriter(conn)
rw := bufio.NewReadWriter(r, w)
term := terminal.NewTerminal(rw, "")
term.SetPrompt(string(term.Escape.Red) + "> " + string(term.Escape.Reset))
rePrefix := string(term.Escape.Cyan) + "Human says:" + string(term.Escape.Reset)
line := "welcome"
fmt.Fprintln(term, rePrefix, line)
for {
line, err := term.ReadLine()
if err == io.EOF {
return nil
}
if err != nil {
return err
}
if line == "" {
continue
}
fmt.Fprintln(term, rePrefix, line)
}
}
func main() {
// Start listening to port 8888 for TCP connection
listener, err := net.Listen("tcp", ":8888")
if err != nil {
fmt.Println(err)
return
}
defer func() {
listener.Close()
fmt.Println("Listener closed")
}()
for {
// Get net.TCPConn object
conn, err := listener.Accept()
if err != nil {
fmt.Println(err)
break
}
go handleConnection(conn)
}
}

Getting bind: address already in use even after closing the connection in golang

I am building a master/slave type system in golang. When the slave(called racer) is up, it pings master telling that it is up and ready to receive data and then it starts listening on a port. The port used for pinging and listening are same but I make sure I am closing the connection after pinging. My use case is to use same port for pinging and listening but I get bind: address already in use error when I use the same port to listen. Sometimes it works sometimes it doesn't. What I am doing wrong?
Complete Code
main.go
package main
import (
"flag"
"log"
"strconv"
"time"
"github.com/goku321/line-racer/master"
"github.com/goku321/line-racer/model"
"github.com/goku321/line-racer/racer"
)
func main() {
log.SetFlags(log.LstdFlags | log.Lshortfile)
nodeType := flag.String("nodeType", "master", "type of node: master/racer")
masterIP := flag.String("masterIP", "127.0.0.1", "ip address of master process")
racers := flag.Int("racers", 2, "number of racers")
racerID := flag.Int("racerID", 0, "unique racer id (0 <= id < number of racers")
laps := flag.Int("laps", 10, "number of lap")
ip := flag.String("ip", "127.0.0.1", "ip address of the node")
port := flag.String("port", "3000", "port to use")
flag.Parse()
_, err := strconv.ParseInt(*port, 10, 64)
if err != nil {
log.Fatalf("error parsing port number: %s", *port)
}
if *nodeType == "master" {
m := master.New(*ip, *port, *racers, *laps)
m.GenerateLaps()
go m.Listen()
m.WaitForRacers()
m.StartRace()
m.PrintLaps()
} else {
r := racer.New(*racerID, *ip, *port, *masterIP)
r.SignalMaster(&model.Message{Source: r.IPAddr + ":" + r.Port})
time.Sleep(time.Second*60)
r.ListenForNewLap()
}
}
racer.go(slave)
package racer
import (
"encoding/json"
"log"
"net"
"os"
"strconv"
"time"
"github.com/goku321/line-racer/model"
)
// Racer represents a racer
type Racer struct {
ID int
IPAddr string
Port string
Master string
Laps [][]model.Point
Status string
}
// SignalMaster sends a signal to master process
// with its coordinates
func (r *Racer) SignalMaster(m *model.Message) {
laddr, err := net.ResolveTCPAddr("tcp", r.IPAddr+":"+r.Port)
if err != nil {
log.Fatalf("error resolving tcp address: %s, reason: %v", r.IPAddr+":"+r.Port, err)
}
raddr, err := net.ResolveTCPAddr("tcp", r.Master+":3000")
if err != nil {
log.Fatalf("error resolving tcp address: %v", err)
}
for {
conn, err := net.DialTCP("tcp", laddr, raddr)
if err != nil {
log.Printf("connecting to master, %v", err)
time.Sleep(time.Second * 5)
} else {
m.Type = "ready"
m.Source = strconv.Itoa(r.ID)
m.Dest = r.Master + ":3000"
err := json.NewEncoder(conn).Encode(&m)
if err != nil {
log.Fatalf("error communicating to master: %v", err)
}
if err = conn.Close(); err != nil {
log.Fatal("unable to close connection")
}
break
}
}
}
// ListenForNewLap waits for master to get new coordinates
func (r *Racer) ListenForNewLap() {
ln, err := net.Listen("tcp", ":"+r.Port)
if err != nil {
log.Fatalf("racer %d: %v - %v", r.ID, err, time.Now())
}
log.Printf("racer %d: listening on %s:%s", r.ID, r.IPAddr, r.Port)
for {
conn, err := ln.Accept()
if err != nil {
log.Fatal(err)
}
go handleConnection(conn, r)
}
}
func handleConnection(conn net.Conn, r *Racer) {
log.Printf("racer %d: new lap from master", r.ID)
var msg model.Message
err := json.NewDecoder(conn).Decode(&msg)
if err != nil {
log.Printf("racer %d: %v", r.ID, err)
}
// close connection here as message has already been received
conn.Close()
if msg.Type == "race" {
r.Laps = append(r.Laps, msg.Coordinates)
r.race(msg.Coordinates)
} else if msg.Type == "kill" {
log.Printf("racer %d: kill signal received. racer will terminate", r.ID)
r.printLaps()
os.Exit(0)
}
}
Some details vary from one implementation to another, but in general, after closing a TCP connection, the underlying system (host OS, usually) has to keep it around for a little while in case of stray duplicate packets.
This connection, which is in TIME_WAIT state, can block further use of the port, making it impossible to create a new listener, unless you give the right underlying settings to the host OS. Since Go 1.5 or so, Go automatically does this on Linux: see issue 9929. What host OS are you using?
If you still get the error, try increasing the milliseconds:
// Sleep a little to avoid this error "bind: address already in use"
time.Sleep(time.Millisecond * 100)
log.Fatal(http.ListenAndServe(":7373", nil))
Thanks to #torek for the idea. I think it's just a notice, not really an error. Example:
2023/02/17 18:10:28 listen tcp :7373: bind: address already in use exit status 1
With go1.20 linux/amd64 and Kernel: Linux 5.13.19-2-MANJARO

How to set the source port when sending udp packets

On the client, I want to set the UDP source port when sending a udp packet.
On the server, I want to know what the UDP source port was received on.
Client:
package main
import (
"net"
)
func main() {
s, err := net.ResolveUDPAddr("udp4", "127.0.0.1:1234")
c, err := net.DialUDP("udp4", nil, s)
if err != nil {
fmt.Println(err)
return
}
}
Server:
package main
import (
"net"
"time"
)
func main() {
s, err := net.ResolveUDPAddr("udp4", "127.0.0.1:1234")
if err != nil {
fmt.Println(err)
return
}
connection, err := net.ListenUDP("udp4", s)
if err != nil {
fmt.Println(err)
return
}
}
In the above client code, is there a way for me to set the source port?
In the above server code, is there a way for me to know the source port used?
https://golang.org/pkg/net/#DialUDP
func DialUDP(network string, laddr, raddr *UDPAddr) (*UDPConn, error)
Both laddr and raddr use UDPAddr struct, but you're not setting laddr.
laddr, err := net.ResolveUDPAddr("udp", "<source_int>:50000")
raddr := net.UDPAddr{IP: net.ParseIP("<dest>"), Port: 50000}
conn, err := net.DialUDP("udp", laddr, &raddr)

bind: cannot assign requested address on UDPclient in local network

As I'm finding quite some examples how to write a go server and client, this works locally on one machine.
Now I'm trying to communicate in my local network between two PCs, one running the go server script, one the client.
However, I can't establish a connection because of the error:
Error: listen udp 192.168.11.6:10001: bind: cannot assign requested address
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x0 pc=0x401376] // ...
Of course I will post my code (client, where the problem occurs):
package main
import (
"fmt"
"net"
"strconv"
"time"
)
func CheckError(err error) {
if err != nil {
fmt.Println("Error: ", err)
}
}
func main() {
ServerAddr, err := net.ResolveUDPAddr("udp", "192.168.11.6:10001")
CheckError(err)
Conn, err := net.ListenUDP("udp", ServerAddr)
CheckError(err)
defer Conn.Close()
i := 0
for {
msg := strconv.Itoa(i)
i++
buf := []byte(msg)
_, err = Conn.WriteToUDP(buf, ServerAddr)
time.Sleep(time.Second * 1)
}
}
Server:
package main
import (
"fmt"
"net"
"os"
)
/* A Simple function to verify error */
func CheckError(err error) {
if err != nil {
fmt.Println("Error: " , err)
os.Exit(0)
}
}
func main() {
ServerAddr,err := net.ResolveUDPAddr("udp",":10001")
CheckError(err)
ServerConn, err := net.ListenUDP("udp", ServerAddr)
CheckError(err)
defer ServerConn.Close()
buf := make([]byte, 1024)
for {
fmt.Println("Starting...")
n,addr,err := ServerConn.ReadFromUDP(buf)
fmt.Println("Received ",string(buf[0:n]), " from ",addr)
ServerConn.WriteToUDP([]byte("hello there!"), addr)
if err != nil {
fmt.Println("Error: ",err)
}
}
}
The client has the local network IP address 192.168.11.8 and the server 192.168.11.6. They can also ping each other, and I'm opening the port when Windows asks for it.
I'm happy about all suggestions. I struggle with this because I only find localhost server client go examples.
Okay, I figured it out. Weird that I had to allow the app to communicate on public networks? While I am on my home network. When starting the server - I had to enable public networks
I figured out that I do not have to open a socket on the client side, but use DialUDP
Also the server needed the full Ip address in
ServerAddr,err := net.ResolveUDPAddr("udp","192.168.11.6:10001")
Improved Client code: (main func)
ServerAddr, err := net.ResolveUDPAddr("udp", "192.168.11.6:10001")
CheckError(err)
buf := make([]byte, 1024)
Conn, err := net.DialUDP("udp", nil, ServerAddr)
CheckError(err)
defer Conn.Close()
i := 0
for {
msg := strconv.Itoa(i)
i++
fmt.Printf(msg)
n, err := Conn.Write([]byte(msg))
CheckError(err)
fmt.Printf("sent %d bytes", n)
n, addr, err := Conn.ReadFromUDP(buf)
if err == nil {
fmt.Printf("%s %s\n", buf, addr)
} else {
fmt.Printf("some err %v\n", err)
}
time.Sleep(time.Second * 1)
}

Golang: Mixing Gin with an UDP server

I'm trying to use both a UDP server to listen continuously to datagrams and a http server, but the string "UDP server up and listening on port..." and command "server.Run()" are never reached.
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"log"
"net"
)
func handleUDPConnection(conn *net.UDPConn) {
buffer := make([]byte, 8096)
n, addr, err := conn.ReadFromUDP(buffer)
if err != nil {
log.Fatal(err)
} else {
fmt.Println("UDP client: ", addr)
fmt.Println("Received from UDP client: ", string(buffer[:n]))
}
}
func main() {
server := gin.Default()
host, port := "localhost", "41234"
udpAddr, err := net.ResolveUDPAddr("udp4", fmt.Sprintf("%s:%s", host, port))
if err != nil {
log.Fatal(err)
}
conn, err := net.ListenUDP("udp", udpAddr)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
server.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "pong"})
})
for {
handleUDPConnection(conn)
}
fmt.Sprintf("UDP server up and listening on port %s\n", port)
server.Run()
}
How can I make it work?
There is an infinite loop in your code.
for {
handleUDPConnection(conn)
}
This will repetedly call the handleUDPConnection function until the program exits without ever moving on to
fmt.Sprintf("UDP server up and listening on port %s\n", port)
server.Run()
Perhaps you want to deal with the connections in a go thread. This would be something more like this:
//define an exit variable
keepListening := true
//spawn a go routine (starts the function on another thread*)
go func() {
for keepListening {
handleUDPConnection(conn)
}
}()
//notify the user that the server is listening
fmt.Sprintf("UDP server up and listening on port %s\n", port)
//run the server (I assume this function call is blocking
server.Run()
//stop the go routine when the server is done running
keepListening = false
Hope this helps!
*a goroutine is not a thread. It can be useful/simple to think of it like that, but they are distinctly different. Here's an article explaining some of the differences and advantages.

Resources