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
Related
ORIGINAL 09/11/2019
conn := createConnection() // or a file handle
go getData(conn)
Is it possible the thread for getData, is in different thread of conn handle. Therefore, it can result an connection error.
---- UPDATED 11/11/2019 09am ----
Senario 1
func createConnection() handler {
... create a socket connection (tcp://.....) or file open handler
return conn
}
func sendData(conn handler, data string) {
conn.send(data)
}
conn := createConnection() // or a file handle
go sendData(conn, "test data")
Senario 2
func createConnection() handler {
... create a socket connection (tcp://.....) or open file handler
return conn
}
func sendData(ch chan handler, data string) {
conn := <- ch
conn.send(data)
}
ch := make(chan conn, 10)
ch <- createConnection() // or a file handle
go sendData(ch, "test data")
Story behind:
I was working on a task to proxy data to a socket server. My solution towards the challenge was using the idea of [Senario 2].
Few of my colleagues are C programmer, work with system level programming. They pointed out that golang channel better only contains data - put file handler in channel can cause unknow problem, such as: the thread for channel get is in different thread of channel put, therefore, the file handler can also missing.
To my understanding, golang should solve the problem by itself already. I, then, asked the question above.
By looking into some of the source code of socket related projects, I think [Senario 1] is fine. However, [Senario 2] is still a question to me.
Again, my question is not [can I pass a file handle to a function], everyone knows "It is a yes". The question is in golang CSP, use go and chan together, with file handler pass through, can it be a problem? Or, more intersetingly: use pointer in golang channel put and channel get can be a problem or not; it is a big "no no" in C by books. If it is fine in golang, how does golang achive it?
---- UPDATED 11/11/2019 10am ----
The question only apply to golang. Such problem does not happen to node.js, since it is single threaded language. The question focuses on threades and file handler. By the fact, I have limited knowledge around the problem, I apologise to ask bad question or provide miss leading infomation.
---- UPDATED 11/11/2019 10:40am ----
I re-confirmed with my colleague, the concern is "everytime code ask for a file handler, system return a number. Howerver, the number is only unique in one process, which means the same file handler number, in different process, may point to different resource. I am not sure goroutine take care it or not."
There is nothing wrong with passing a connection handle to a separate goroutine as long as you are careful about the following:
Do not close the handle while the goroutine is working, or write the goroutine to deal with it.
If you are using the handle from multiple goroutines, make sure the connection you're dealing with is thread-safe, or put a lock around it.
Be clear and explicit about who's going to close it. The goroutine may close it when it is done, or another goroutine closes it when all work using the handle is done.
I’m just getting started with Golang and the net/rpc package. I’m trying to understand when you might use the asynchronous client.Go() call over the client.Call() method most examples online use. Would calling client.Call asynchronously via something like
go client.Call(...)
essentially be the same as using the client.Go call? I’ve seen this example online too (for example when calling multiple simultaneous RPCs).
As documented:
Go invokes the function asynchronously. It returns the Call structure representing the invocation. The done channel will signal when the call is complete by returning the same Call object. If done is nil, Go will allocate a new channel. If non-nil, done must be buffered or Go will deliberately crash.
What this means is that it issues the command, but does not wait for it to finish.
By contrast:
Call invokes the named function, waits for it to complete, and returns its error status.
Neither method executes in a goroutine directly*--this is left as an exercise for the caller (so an argument might be made that Go is a misnomer).
If you look at the source to Call, perhaps it is more clear:
func (client *Client) Call(serviceMethod string, args interface{}, reply
interface{}) error {
call := <-client.Go(serviceMethod, args, reply, make(chan *Call, 1)).Done
return call.Error
}
So in actuality, Call is a wrapper around Go, which waits for the operation to complete, whereas Go is the underlying function, which leaves waiting up to the caller.
*Clearly, in the background, a goroutine is involved somewhere, since this is a non-blocking operation.
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.
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.
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()
}
}()