I'm assuming I can run a service on port 3000 like many other code samples I've seen on Github.
Now I am trying to improve my code so that it looks for an open port in case 3000 is in use:
for port := 3000; port <= 3005; port++ {
fmt.Println(port)
err := http.ListenAndServe(":"+strconv.Itoa(port), nil)
if err == nil {
fmt.Println("lk is serving", dirPath, "from http://0.0.0.0:", string(port))
open.Start("http://0.0.0.0:" + string(port))
}
}
However it blocks on the http.ListenAndServe line and doesn't open.Start my browser. I'm told I should use goroutines but I am still a bit bewildered how to use them in this context.
This is a "client" Web app so I do need it to invoke my browser.
Instead of calling ListenAndServe, create the Listener in the application and then call Serve. When creating the listener, request a free port by specifying the listener address as ":0":
ln, err := net.Listen("tcp", ":0")
if err != nil {
// handle error
}
Once the listener is open, you can start the browser:
open.Start("http://" + ln.Addr().String())
and then start the server:
if err := http.Serve(ln, nil); err != nil {
// handle error
}
There's no need to use a goroutine.
The code above uses addr.String() to format the listener's address. If you do need to get the port number for some reason, use a type assertion:
if a, ok := ln.Addr().(*net.TCPAddr); ok {
fmt.Println("port", a.Port)
}
Related
I'd like to connect from Go to the running instance of the Memgraph database. I'm using Docker and I've installed the Memgraph Platform. What exactly do I need to do?
The procedure for connecting fro Go to Memgraph is rather simple. For this you need to use Bolt protocol. Here are the needed steps:
First, create a new directory for your app, /MyApp, and position yourself in it. Next, create a program.go file with the following code:
package main
import (
"fmt"
"github.com/neo4j/neo4j-go-driver/v4/neo4j"
)
func main() {
dbUri := "bolt://localhost:7687"
driver, err := neo4j.NewDriver(dbUri, neo4j.BasicAuth("username", "password", ""))
if err != nil {
panic(err)
}
// Handle driver lifetime based on your application lifetime requirements driver's lifetime is usually
// bound by the application lifetime, which usually implies one driver instance per application
defer driver.Close()
item, err := insertItem(driver)
if err != nil {
panic(err)
}
fmt.Printf("%v\n", item.Message)
}
func insertItem(driver neo4j.Driver) (*Item, error) {
// Sessions are short-lived, cheap to create and NOT thread safe. Typically create one or more sessions
// per request in your web application. Make sure to call Close on the session when done.
// For multi-database support, set sessionConfig.DatabaseName to requested database
// Session config will default to write mode, if only reads are to be used configure session for
// read mode.
session := driver.NewSession(neo4j.SessionConfig{})
defer session.Close()
result, err := session.WriteTransaction(createItemFn)
if err != nil {
return nil, err
}
return result.(*Item), nil
}
func createItemFn(tx neo4j.Transaction) (interface{}, error) {
records, err := tx.Run(
"CREATE (a:Greeting) SET a.message = $message RETURN 'Node ' + id(a) + ': ' + a.message",
map[string]interface{}{"message": "Hello, World!"})
// In face of driver native errors, make sure to return them directly.
// Depending on the error, the driver may try to execute the function again.
if err != nil {
return nil, err
}
record, err := records.Single()
if err != nil {
return nil, err
}
// You can also retrieve values by name, with e.g. `id, found := record.Get("n.id")`
return &Item{
Message: record.Values[0].(string),
}, nil
}
type Item struct {
Message string
}
Now, create a go.mod file using the go mod init example.com/hello command.
I've mentioned the Bolt driver earlier. You need to add it with go get github.com/neo4j/neo4j-go-driver/v4#v4.3.1. You can run your program with go run .\program.go.
The complete documentation is located at Memgraph site.
I use memcache for caching and the client I use is https://github.com/bradfitz/gomemcache. When I tried initiate new client with dummy/invalid server address and then pinging to it, it return no error.
package main
import (
"fmt"
m "github.com/bradfitz/gomemcache"
)
func main() {
o := m.New("dummy_adress")
fmt.Println(o.Ping()) // return no error
}
I think it suppose to return error as the server is invalid. What do I miss?
It looks like the New() call ignores the return value for SetServers:
func New(server ...string) *Client {
ss := new(ServerList)
ss.SetServers(server...)
return NewFromSelector(ss)
}
The SetServers() function will only set the server list to valid servers (in
your case: no servers) and the Ping() funtion will only ping servers that are
set, and since there are no servers set it doesn't really do anything.
This is arguably a feature; if you have 4 servers and one is down then that's
not really an issue. Even with just 1 server memcache is generally optional.
You can duplicate the New() logic with an error check:
ss := new(memcache.ServerList)
err := ss.SetServers("example.localhost:11211")
if err != nil {
panic(err)
}
c := memcache.NewFromSelector(ss)
err = c.Ping()
if err != nil {
panic(err)
}
Which gives:
panic: dial tcp 127.0.0.1:11211: connect: connection refused
I am using gorilla mux to create a golang server to support a simple health GET endpoint.
The endpoint responds with a status of ok whenver the server is up.
I see a lot of connections (over 400) in CLOSE_WAIT state on one system.
This does not happen on other systems with the same code.
Output of netstat (9003 is my server port):
tcp 164 0 ::1:9003 ::1:60702 CLOSE_WAIT -
tcp 164 0 ::1:9003 ::1:44472 CLOSE_WAIT -
tcp 164 0 ::1:9003 ::1:31504 CLOSE_WAIT -
This seems to imply that I have a connection I need to close.
Most of the questions I read online seem to suggest that open connections pertain to the client not issuing a response.body.close() after a GET.
As per https://blog.cloudflare.com/the-complete-guide-to-golang-net-http-timeouts/, I could add read/write timeouts on server side but I would like to understand the root cause of CLOSE_WAITS before adding the improvements.
Am I missing any close on the server side?
My code is below:
import "github.com/gorilla/mux"
...
func (server *Srvr) healthHandler(w http.ResponseWriter, r *http.Request) {
resp := map[string]string{"status": "ok"}
respJSON, err := json.Marshal(resp)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(w, "Error creating JSON response %s", err)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(respJSON)
}
// Load initializes the servers
func Load(port string) *Srvr {
srvrPort := ":" + port
log.Infof("Will listen on port %s", srvrPort)
serverMux := mux.NewRouter()
srvr := &Srvr{Port: port, Srv: &http.Server{Addr: srvrPort, Handler: serverMux}}
serverMux.HandleFunc("/api/v1.0/health", srvr.healthHandler).Methods("GET")
return srvr
}
// Run starts the server
func (server *Srvr) Run() {
log.Info("Starting the server")
// Starting a server this way to allow for shutdown.
// https://stackoverflow.com/questions/39320025/how-to-stop-http-listenandserve
err := server.Srv.ListenAndServe()
if err != http.ErrServerClosed {
log.Fatalf("ListenAndServe(): %s", err)
}
}
// Main resides outside the server package
func main() {
srvr := server.Load("9003")
// Now that all setup is done successfully, lets start the server
go srvr.Run()
// An unrelated forever loop executes below for different business logic
for {
glog.Info("Evaluation iteration begins now")
...
time.Sleep(time.Duration(evalFreq) * time.Minute)
}
}
I am trying to make a telnet client using the go-telnet library. I am able to connect to the server, but I was expecting to receive some data to login in with user and password.
But I don't get any message. What I could do until now is just send a message to the server and the server prints it.
If I connect using a regular telnet client first thing I have to do is to log in with user and password. I want to replicate this using my own client.
I don't see any examples on GitHub on how to send or receive messages so I am a little confused.
Here is my current code:
func main() {
err = telnet.DialToAndCall("192.168.206.226:23", caller{})
if err != nil {
fmt.Println(err)
os.Exit(1)
}
}
type caller struct {}
func (c caller) CallTELNET(ctx telnet.Context, w telnet.Writer, r telnet.Reader) {
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
}
Are there any other steps I need to do when connecting? Or am I doing something wrong?
edit (reading part):
//var data []byte
for {
//numBytes, err := conn.Read(data)
reader := bufio.NewReader(os.Stdin)
fmt.Println(reader.ReadString('\n'))
}
I am having trouble closing a listener so that I can reopen it on the same port. I am writing a proxy server that is hot-configurable - i.e what it does (redirects/blocks etc) can be adjusted on the fly. The proxy runs in a go routine. The problem I am having is when I reconfigure the listener and proxy the listener is still using that port from the previous configuration. (FYI listener is a global pointer)
I'm trying something like:
to kill the listener:
func KillProxy() {
if listener != nil {
log.Println(" *** TRYING TO STOP THE PROXY SERVER")
(*listener).Close()
listener = nil
}
}
before reconfiguring it like:
log.Println("listener (S1): ", listener)
if listener == nil {
// Start the listener to listen on the connection.
l, err := net.Listen(CONN_TYPE, CONN_HOST + ":" + CONN_PORT)
if err != nil {
log.Println("error here: ", err)
}
listener = &l //set it as a pointer to the newly created listener
}
log.Println("listener (S2): ", listener)
however that doesnt seem to work - I get the error:
listener (S1):
error here: listen tcp 0.0.0.0:8080: bind: address already in use
listener (S2): 0xc2080015e0
and then a massive stack trace that summizes to:
panic: runtime error: invalid memory address or nil pointer dereference
EDIT IN RESPONSE TO JIM:
Interesting re pointers. OK. I am not handling waiting for the socket to close, Im not sure how that should be done. The proxy library I am using is this one: https://github.com/abourget/goproxy. The order things happen is:
KillProxy()
refreshProxy()
refreshProxy holds the code posted above that tries to repurpose the listener. The last thing that happens in refreshProxy() is:
go http.Serve(*listener, proxy)
So if I revert to listener being a global variable, not a pointer I can make KillProxy():
func KillProxy() {
if listener != nil {
listener.Close()
listener = nil
}
}
and then setup the listener again as
listener, err := net.Listen(CONN_TYPE, CONN_HOST + ":" + CONN_PORT)
if err != nil {
log.Println("error here: ", err)
}
However I don't know how to wait and check whether the socket has closed before trying to re create the listener object?
Ok this is far from perfect, but the only way I found of not having it error out on me was to artifically put a delay in my code so the socket had time to close.
This isn't great as it means the proxy is down for 2 seconds while the socket closes, but at least it doesnt error out.
If someone has a better solution I would like to hear it
func KillProxy() {
if listener != nil {
listener.Close()
log.Println("waiting for socket to close")
time.Sleep(2 * time.Second)
}
}