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

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.

Related

Relay data between two different tcp clients in golang

I'm writing a TCP server which simultaneously accepts multiple connections from mobile devices and some WiFi devices (IOT). The connections needs to be maintained once established, with the 30 seconds timeout if there is no heartbeat received. So it is something like the following:
// clientsMap map[string] conn
func someFunction() {
conn, err := s.listener.Accept()
// I store the conn in clientsMap
// so I can access it, for brevity not
// shown here, then:
go serve(connn)
}
func serve(conn net.Conn) {
timeoutDuration := 30 * time.Second
conn.SetReadDeadline(time.Now().Add(timeoutDuration))
for {
msgBuffer := make([]byte, 2048)
msgBufferLen, err := conn.Read(msgBuffer)
// do something with the stuff
}
}
So there is one goroutine for each client. And each client, once connected to the server, is pending on the read. The server then processes the stuff read.
The problem is that I sometimes need to read things off one client, and then pass data to another (Between a mobile device and a WiFi device). I have stored the connections in clientsMap. So I can always access that. But since each client is handled by one goroutine, shall I be passing the data from one client to another by using a channel? But if the goroutine is blocked waiting for a pending read, how do I make it also wait for data from a channel? Or shall I just obtain the connection for the other party from the clientsMap and write to it?
The documentation for net.Conn clearly states:
Multiple goroutines may invoke methods on a Conn simultaneously.
So yes, it is okay to simply Write to the connections. You should take care to issue a single Write call per message you want to send. If you call Write more than once you risk interleaving messages from different mobile devices. This implies calling Write directly and not via some other API (in other words don't wrap the connection). For instance, the following would not be safe:
json.NewEncoder(conn).Encode(myValue) // use json.Marshal(myValue) instead
io.Copy(conn, src) // use io.ReadAll(src) instead

Convention when using Reader interface inside select statement

I've wrapped a queue to implement the Writer and Reader interfaces (for pushing and popping, respectively).
I need to continuously listen to the queue, and handle every message that comes through. This is simple when the queue is represented as a channel, but more difficult otherwise:
loop:
for {
var data []byte
select {
case <-done:
break loop
case _, err := queue.Read(data):
fmt.Println(string(data))
}
}
What's the proper way to do this? Read here is blocking - it waits until the queue has a message.
Is there a better, more idiomatic way to achieve this?
It’s harder to take a synchronous API (like queue.Read as you described above) and make it asynchronous than it is to do the opposite.
The idea would be to create a new goroutine (using, for example go func() {...}) and have that goroutine execute the read and write the output to a channel.
Then the first goroutine would block on that channel and the one it’s already blocking on.
This has the potentially to leave orphaned resources for a little while if the read takes to long but if you have a synchronous API, it’s the best you can do.

Unbuffered bidirectional data streaming with gRPC: how to get the size of the client-side buffer?

I am streaming data from a server to a client and I would like the server not to read and send more data than the client's buffer size.
Given:
service StreamService {
rpc Stream(stream Buffer) returns (stream Buffer);
}
message Buffer {
bytes data = 1;
}
My client's program basically looks like:
func ReadFromServer(stream StreamService_StreamClient, buf []byte) (n int, err error) {
// I actually don't need more than len(buf)...
// How could I send len(buf) while stream is bidirectional...?
buffer, err := stream.Recv()
if err != nil {
return 0, err
}
n = copy(buf, buffer.Data)
// buf could also be smaller than buffer.Data...
return n, nil
}
So how could I send len(buf) while the RPC's stream is bidirectional, i.e. the send direction is used by another independent stream of data? Note that I don't use client or server-side buffering to avoid loosing data when one of them is terminated (my data-source is an I/O).
gRPC provides no mechanism for this. It only provides push-back when a sender needs to slow down. But there will still be buffering happening internally and that is not exposed because gRPC is message-based, not byte-based.
There's really only two options in your case:
Server chunks responses arbitrarily. The client Recv()s when necessary and any extra is manually managed for later.
The client sends a request asking for a precise amount to be returned, and then waits for the response.
Note that I don't use client or server-side buffering to avoid loosing data when one of them is terminated (my data-source is an I/O).
This isn't how it works. When you do a Send() there is no guarantee it is received when the call returns. When you do a Recv() there is no guarantee that the message was received after the recv call (it could have been received before the call). There is buffering going on, period.
I think there's no built-in solution for that. The use-case looks little bit weird: why server must care about client's state at all? If it really needs to, you should extend your bidirectional stream: the client must request byte slices of a particular size (according to the own buffer size and other factors).
By the way, you may find useful message size limit settings GRPC client and server:
https://godoc.org/google.golang.org/grpc#MaxMsgSize https://godoc.org/google.golang.org/grpc#WithMaxMsgSize

is it wrong to treat panic / recover as throw / catch

Speaking as a new go enthusiast trying to work with the go way of error handling. To be clear - I like exceptions.
I have a server that accepts a connection , processes a set of requests and replies to them. I found that I can do
if err != nil{
panic(err)
}
in the deep down processing code
and have
defer func() {
if err := recover(); err != nil {
log.Printf("%s: %s", err, debug.Stack()) // line 20
}
}()
in the client connection code (each connection is in a goroutine). This nicely wraps everything up, forcefully closes the connection (other defers fire) and my server continues to hum along.
But this feels an awful lot like a throw/catch scenario - which golang states it doesn't support. Questions
is this stable. ie recovering a panic is an OK thing to do as an
ongoing way of life. Its not intended to just slightly defer an
immediate shutdown
I looked for a discussion on this topic and did not find it anywhere - any pointers?
I feel that the answer is 'yes it works' and can be used inside you own code, but panic should NOT be used by a library intended for wider use. The standard and polite way for a library to behave is by error returns
Yes, you can do what you suggest. There are some situations within the standard packages where panic/recover is used for handling errors. The official Go blog states:
For a real-world example of panic and recover, see the json package
from the Go standard library. It decodes JSON-encoded data with a set
of recursive functions. When malformed JSON is encountered, the parser
calls panic to unwind the stack to the top-level function call, which
recovers from the panic and returns an appropriate error value (see
the 'error' and 'unmarshal' methods of the decodeState type in
decode.go).
Some pointers:
Use error for your normal use cases. This should be your default.
If your code would get clearer and simpler by using a panic/recover (such as with a recursive call stack), then use it for that particular case.
Never let a package leak panics. Panics used within a package should be recovered within the package and returned as an error.
Recovering from a panic is stable. Don't worry about continuing execution after a recover. You can see such behavior in standard library such as with the net/http package which recovers from panics within handlers to prevent the entire http server to go crash when panicing on a single request.
Generally most methods won't panic, they will return an error instead, and there's a bit of an overhead of using defer.
So yes, it does work, but the "proper" / "go" way is to return an error instead of using panic / recover.

Checking if a channel has a ready-to-read value, using Go

How do I check whether a channel has a value for me to read?
I don't want to block when reading a channel. I want to see whether it has a value. If it does have one, I'll read it. If it doesn't have one (yet), I'll do something else and check back again later.
The only non-blocking operation I know of to read from a channel is inside a select block having a default case :
select {
case x, ok := <-ch:
if ok {
fmt.Printf("Value %d was read.\n", x)
} else {
fmt.Println("Channel closed!")
}
default:
fmt.Println("No value ready, moving on.")
}
Please try the non-blocking here
Note about previous answers: the receive operator itself is now a blocking operation, as of Go 1.0.3 . The spec has been modified. Please try the blocking here (deadlock)
If you're doing this often then it's probably not a great design and you might be better off spawning another goroutine to do whatever work you're planning to do when there isn't anything to read from the channel. The synchronous/blocking nature of Go's channels make code easier to read and reason about while the scheduler and cheap goroutines means that async calls are unnecessary since waiting goroutines take up very little resources.
Unfortunately, the previous answers are incorrect. The spec clearly says that you CAN use channels this way using len() function, but only if you specified the channel capacity - the buffer length for a channel while making it. If you omitted a channel capacity while making it - the channel operations are always blocking.
You don't, at least not for synchronous (unbuffered) channels. There is no way to tell if a value is waiting without asking to take the value from the channel.
For buffered channels, you technically can use the len function to do what you describe, but you really, really shouldn't. Your technique is invalid.
The reason is that it represents a race condition. Given channel ch, your goroutine might see that len(ch) > 0 and conclude that there is a value waiting. It cannot conclude however, that it can read from the channel without blocking--another goroutine might empty the channel between the time you check len and the time your receive operation runs.
For the purpose you described, use select with a default case as Ripounet showed.
WARNING: This is no longer accurate, see the answer below.
From the docs:
If a receive expression is used in an
assignment or initialization of the
form
x, ok = <-ch
x, ok := <-ch
var x, ok = <-ch
the receive operation becomes
non-blocking. If the operation can
proceed, the boolean variable ok will
be set to true and the value stored in
x; otherwise ok is set to false and x
is set to the zero value for its type
In most cases relying on such information is a really bad design choice. Not even saying about how it's dirty in it's implementation.
So, do not implement the following steps to detect if channel is ready for read at runtime:
define hchan waitq sudog structs as defined here - https://golang.org/src/runtime/chan.go
use "unsafe" package to cast channel to pointer to hchan struct
read sendq field of this struct to get listeners
read first sudog and read msg field from there.
cast msg to the appropriate type for the channels using "reflect" and "unsafe"

Resources