How do WriteMessage and ReadMessage in Gorilla Websocket work? - go

I'm working with Gorilla Websocket and curious about how the WriteMessage and ReadMessage functions work.
Does the WriteMessage function send the bytes data to the client synchronously? Or Does the ReadMessage actively fetch the data from the server (according to the documentation, we need to create an event loop to call the ReadMessage function).
What happened if the server kept calling WriteMessage, but no one read the message (the client calls the ReadMessage function through event loop), is the data is lost, or is it kept until the next read request came? Thank You.

Does the WriteMessage function send the bytes data to the client synchronously?
WriteMessage writes the data to the underlying network connection.
The operating system network connection maintains a buffer of data to transmit to the peer. Data is removed from the buffer when the peer acknowledges that the peer received data.
Write to the operating system network connection returns after all of the application data is added to the buffer. Write can block waiting for space in the buffer.
It is almost always the case that the application write call returns before the peer receives the data. A successful call to WriteMessage does imply that the peer application read the data.
Or Does the ReadMessage actively fetch the data from the server (according to the documentation, we need to create an event loop to call the ReadMessage function).
ReadMessage calls read on the underlying network connection.
The operating system buffers some amount of data received from peer.
Read on the operating network connection blocks until data is available in the buffer.
What happened if the server kept calling WriteMessage, but no one read the message.
WriteMessage will eventually block waiting for space in the operating system transmit buffer.
Use a write deadline to protect against blocking forever on a dead or stuck peer.
is the data is lost, or is it kept until the next read request came?
The data is held in operating system transmit and receive buffers.
Application write to the websocket connection blocks when the transmit buffer is full.
The data is only lost if the peer application terminates before the peer application reads the data.

You can find source code for that function here: https://github.com/gorilla/websocket/blob/c3dd95aea9779669bb3daafbd84ee0530c8ce1c1/conn.go#L751-L774
And it looks like this is is blocking/sync method.
As per tracking They creating writer here: https://github.com/gorilla/websocket/blob/c3dd95aea9779669bb3daafbd84ee0530c8ce1c1/conn.go#L766
w, err := c.NextWriter(messageType)
Then they are writing the data:
if _, err = w.Write(data); err != nil {
return err
}
And this is blocking because they are closing connection in the last line of that function, so writing must be done at this moment.
This is behavior of io.WriteCloser interface returned into w variable.
What happened if the server kept calling WriteMessage, but no one read the message (the client calls the ReadMessage function through event loop), is the data is lost, or is it kept until the next read request came? Thank You.
You should set Write/Read timeouts.
Library is not repeating sending the data for you. You need to implement this logic in your application.
If server is up and receive your connection, (probably) it will read your message(if it is not stopped before perform your data).
If you sent message and server was dead(did not receive your message), your data is lost.
Additional reference:
The w.Write function: https://github.com/gorilla/websocket/blob/c3dd95aea9779669bb3daafbd84ee0530c8ce1c1/conn.go#L650-L675
The io.WriteCloser interface desc: https://golang.org/pkg/io/#WriteCloser
Gorila Websocket timeouts: https://pkg.go.dev/github.com/gorilla/websocket#Conn.SetReadDeadline
Timeouts documentation for Gorila: https://pkg.go.dev/github.com/gorilla/websocket#Conn.SetReadDeadline

Related

Trying to send a FIX api message to ctrader server using Ruby but receiving no response

Trying to see if I can get a response from ctrader server.
Getting no response and seems to hang at "s.recv(1024)". So not sure what could be going wrong here. I have limited experience with sockets and network coding.
I have checked my login credentials and all seems ok.
Note: I am aware of many FIX engines that are available for this purpose but wanted to
try this on my own.
ctrader FIX guides
require 'socket'
hostname = "h51.p.ctrader.com"
port = 5201
#constructing a fix message to see what ctrader server returns
#8=FIX.4.4|9=123|35=A|49=demo.ctrader.*******|56=cServer|57=QUOTE|50=QUOTE|34=1|52=20220127-16:49:31|98=0|108=30|553=********|554=*******|10=155|
fix_message = "8=FIX.4.4|9=#{bodylengthsum}|" + bodylength + "10=#{checksumcalc}|"
s = TCPSocket.new(hostname, port)
s.send(fix_message.force_encoding("ASCII"),0)
print fix_message
puts s.recv(1024)
s.close
Sockets are by default blocking on read. When you call recv that call will block if no data is available.
The fact that your recv call is not returning anything, would be an indication that the server did not send you any reply at all; the call is blocking waiting for incoming data.
If you would use read instead, then the call will block until all the requested data has been received.
So calling recv(1024) will block until 1 or more bytes are available.
Calling read(1024) will block until all 1024 bytes have been received.
Note that you cannot rely on a single recv call to return a full message, even if the sender sent you everything you need. Multiple recv calls may be required to construct the full message.
Also note that the FIX protocol gives the msg length at the start of each message. So after you get enough data to see the msg length, you could call read to ensure you get the rest.
If you do not want your recv or read calls to block when no data (or incomplete data) is available, then you need to use non-blocking IO instead for your reads. This is complex topic, which you need to research, but often used when you don't want to block and need to read arbitary length messages. You can look here for some tips.
Another option would be to use something like EventMachine instead, which makes it easier to deal with sockets in situations like this, without having to worry about blocking in your code.

Request body too large causing connection reset in Go

I have a simple multipart form which uploads to a Go app. I wanted to set a restriction on the upload size, so I did the following:
func myHandler(rw http.ResponseWriter, request *http.Request){
request.Body = http.MaxBytesReader(rw, request.Body, 1024)
err := request.ParseMultipartForm(1024)
if err != nil{
// Some response.
}
}
Whenever an upload exceeds the maximum size, I get a connection reset like the following:
and yet the code continues executing. I can't seem to provide any feedback to the user. Instead of severing the connection I'd prefer to say "You've exceeded the size limit". Is this possible?
This code works as intended. Description of http.MaxBytesReader
MaxBytesReader is similar to io.LimitReader but is intended for
limiting the size of incoming request bodies. In contrast to
io.LimitReader, MaxBytesReader's result is a ReadCloser, returns a
non-EOF error for a Read beyond the limit, and closes the underlying
reader when its Close method is called.
MaxBytesReader prevents clients from accidentally or maliciously
sending a large request and wasting server resources.
You could use io.LimitReader to read just N bytes and then do the handling of the HTTP request on your own.
The only way to force a client to stop sending data is to forcefully close the connection, which is what you're doing with http.MaxBytesReader.
You could use a io.LimitReader wrapped in a ioutil.NopCloser, and notify the client of the error state. You could then check for more data, and try and drain the connection up to another limit to keep it open. However, clients that aren't responding correctly to MaxBytesReader may not work in this case either.
The graceful way to handle something like this is using Expect: 100-continue, but that only really applies to clients other than web browsers.

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()
}
}()

Windows socket write() is blocked by a read() unexpectedly

(this is an updated repost of a previously asked question, posted with old account which I've lost the credentials for)
I'm writing a client-server program, where the client is C++/winapi and the server is C#/.net.
socket is an AF_INET/ SOCK_STREAM and I'm using Readfile() and WriteFile() for socket IO at client.
the client have a loop where it reads from server (and may block the calling thread [denote t1] , which is fine with me). it also have another thread [denote t2] , that wait on an Event object with a timeout.
if the timeout is reached (and the Event is yet to be singled) the t2 thread, will write (exacly on byte) on the same socket.
The problem I have, is that it seems like the write won't return untill the read on t1 returns (in some legitimate scnerions it will never happen) , as if the socket was not full-duplex.
I've checked it buttom to top, there are no other thread-related comlications. I acctually ran the client from a diffrent machine, and used wireshark to sniff traffic. After the timeout was reached, there was nothing on the wire (no matter how long I wait) , untill I wrote some data from server side (so the read() on t1 returned) - and just right after that, the write() of client is finally transmitted.
As I explained in your earlier question, sockets are full duplex. A read in one thread will not block a write in another thread, and vice versa.

Block TCP-send till ACK returned

I am programming a client application sending TCP/IP packets to a server. Because of timeout issues I want to start a timer as soon as the ACK-Package is returned (so there can be no timeout while the package has not reached the server). I want to use the winapi.
Setting the Socket to blocking mode doesn't help, because the send command returns as soon as the data is written into the buffer (if I am not mistaken). Is there a way to block send till the ACK was returned, or is there any other way to do this without writing my own TCP-implementation?
Regards
It sounds like you want to do the minimum implementation to achieve your goal. In this case you should set your socket to blocking, and following the send which blocks until all data is sent, you call recv which in turn will block until the ACK packet is received or the server end closes or aborts the connection.
If you wanted to go further with your implementation you'd have to structure your client application in such a way that supports asynchronous communication. There are a few techniques with varying degrees of complexity; polling using select() simple, event model using WSASelectEvent/WSAWaitForMultipleEvents challenging, and the IOCompletionPort model which is very complicated.
peudocode... Will wait until ack is recevied, after which time you can call whatever functionallity you want -i chose some made up function send_data.. which would then send information over the socket after receiving the ack.
data = ''
while True
readable, writable, errors = select([socket])
if socket in readble
data += recv(socket)
if is_ack(data)
timer.start() #not sure why you want this
break
send_data(socket)

Resources