Golang websocket's SetWriteDeadline function - go

Go's websockets have a SetWriteDeadline() function to set the connection's network write deadline. Do I need to set it before every data sending or it can be done just once when the connection is created?

For it to be useful at all, set it every time. Note that it takes a time.Time, not a time.Duration:
SetWriteDeadline(t time.Time) error

Set it once.
PS I checked it myself, it's a simple code.

Related

How to set a write deadline for GoLang bufio.Writer?

I am using buffio.Writer in GoLang as follows.
conn, err := net.Dial("tcp", address) // address is of form ip:port
w := bufio.NewWriter(conn)
w.WriteByte(code) // code is a byte
w.Write(data) // data is a byte buffer
w.Flush()
I am trying to modify the above code so that the write() events have a deadline: when the deadline is passed, the write() event will return irrespective of the fact that it was successful or not.
In GoLang its possible to have a deadline, if the conn (connection object) is directly used for writing using conn.SetWriteDeadline(time.Now().Add(n * time.Second)). However, when I use bufifo.writer object, which is essentially a wrapper around conn for buffered IO, there is no API to set a deadline.
While its possible to use conn.SetWriteDeadline(time.Now().Add(n * time.Second)) and use conn.Write(b), its very inefficient since it doesn't buffer the write events (thus a lot of context switches)
Is there a way in GoLang where I can use buffered IO with a writeDeadline()?
Thanks
There are two cases to note here.
If you want to have per write() deadline, then its not possible to use buffering. When you use buffering, then the actual write() is triggered when the buffer is full. So technically its not possible to know when your write() is completed. In this case, you are essentially using conn.write() and you can use conn.SetWriteDeadline(time.Now().Add(n * time.Second)).
In the second case, as #icza has mentioned in the comment, you can set the deadline in the underlying conn object, and the buffio.writer() wrapper will adhere to this rule. While this is semantically correct, it doesn't provide the networking abstraction you want.

Go server : get non-empty net.Conn

I have server with several net.Conn. How can I get list of net.Conn which have unreaded messages (without using active waiting) ?
I don't think you can.
If you try to read from the net.Conn with its Read method, it will block until there is data. So just start a goroutine for each net.Conn, and read from it in the goroutine.
The example in the net package's documentation does exactly that: https://pkg.go.dev/net#example-Listener

Disabling a deadline in golang TCP

I want to set a deadline on client connection, he must do something within the first 10 seconds or else get disconnected, if he does do something, I want to remove the deadline.
// meConn = *TCPConn
c.meConn.SetDeadline(time.Now().Add(10 * time.Second))
But the documentation doesn't say anything about disabling the deadline.
Also, is it safe to keep changing the deadline when a certain condition is met?
To reset the deadline, you can call SetDeadline with a "zero" value as the docs stay. This the "zero" value can be set with:
conn.SetDeadline(time.Time{})
It states:
// SetReadDeadline sets the deadline for future Read calls.
// A zero value for t means Read will not time out.
SetReadDeadline(t time.Time) error
In the documentation for SetReadDeadLine
so you will need to pass in zero when a client sends what you expect.
and the SetDeadLine says it is setting both the reader and the writer, so make sure you also meant to set the writer.
// SetDeadline sets the read and write deadlines associated
// with the connection. It is equivalent to calling both
// SetReadDeadline and SetWriteDeadline.

Go Context with http.server

In order to test a server that I am writing, I want to be able to start and stop it in the testing framework.
To do so, I am hoping I can integrate the context package in with the http.Server struct. I want to be able to stop the server when I call the Done function and the ctx.Done() channel returns something.
What I would love to do would be to just modify the http.Server.Serve() method, to accept a context.Context and check if it is done, on each iteration of the for loop, like this:
func (srv *server) Serve(ctx context.Context, l net.Listener) error {
defer l.Close()
var tempDelay time.Duration // how long to sleep on accept failure
for {
select {
case <-ctx.Done():
return nil
default:
}
... rest is same as original
However it seems like if I wanna add that check inside the for loop, I would have to rewrite a lot of the methods, because this method calls other private methods (like http.server.srv), which in turn call other private methods....
I also notice that the for loop will stop when the Accept() method on the listener returns an error.
However, I can't seem to figure out a way to get a listener to output an error from it's accept method without accessing its private methods as well.
It seems like I am doing something very stupid and wrong if I have to copy and paste half the http library just to let the server stop using the context package.
I know there are lots of solutions around for supporting context canceling for the ServeHTTP function, but that isn't what I am talking about. I wanna pass a context to the whole server, not just to each incoming request.
Is this just impossible?
Use httptest.Server to create a server that you can start and stop in tests.
If you do use the http.Server directly, you can break the Serve loop by closing the net.Listener. When a net.Listener is closed, any blocked Accept operations are unblocked and return errors. The Serve function returns if Accept returns a permanent error.

using Go redis client (Redigo)

I'm using GO redis client redigo to write image to ~20 redis servers.
speed is an important factor here and I'm just sending set commands to the redis so I'm using Send and Flush without calling Receive.
after a few hours I'm getting "connection reset by peer" on the client.
I was wondering, does it have something to do with the fact that I don't call Receive?
maybe my RX queue just getting to its max capacity because I don't empty it with Receive?
Thank you.
An application must call Receive to clear the responses from the server and to check for errors. If the application is not pipelining commands, then it's best to call Do. Do combines Send, Flush and Receive.
If you don't care about errors, then start a goroutine to read the responses:
go func(c redis.Conn) {
for c.Err() == nil {
c.Receive()
}
}()

Resources