[Gambas-user] Trouble writing to Accepted Socket stream

Tobias Boege taboege at gmail.com
Sat Mar 30 11:27:03 CET 2019


On Sat, 30 Mar 2019, T Lee Davidson wrote:
> On 3/30/19 4:37 AM, Tobias Boege wrote:
> > The Write event is supposed (as per source code) to only fire when you have
> > enqueued data to be sent. It works like this:
> > 
> >   Write #Socket --> gb.net tries to send it, installs a Write event
> >   callback --> which when fired raises the Gambas event and deinstalls
> >   itself again until the next write happens
> 
> So then the documentation for the Socket.Write event handler saying, "This
> event is raised when the socket is ready for writing," is not correct?
> 
> Should that be, "This event is raised when there is enqueued data ready to
> be written to the socket"? Or should it be, "This event is raised when there
> is enqueued data to be written to the socket and the socket is ready to
> accept it"? I think I'm confused. Of what use is a callback if one does not
> have access to the data already in the 'pipe'?
> 

This event is raised when the internal buffers allow more data to be written
to the socket without blocking the application. But a large Write may still
block because the buffers were not _that_ empty.

> > And that's how I take it you should use this event: your application appends
> > to an arbitrary-sized Gambas String buffer the data which should be sent,
> > and your Write event handler takes care of feeding the small kernel buffers
> > from that string; the Write event will be raised whenever you can feed more.
> 
> How exactly would that be done? If the Write event doesn't fire until one has *already* written to the stream, what good is it?
> 

What is the alternative? Firing it constantly after a connection was
established?

  "Hey, you could be writing data now" -- "I don't have data to write"
  "Hey, you could be writing data now" -- "I don't have data to write"
  "Hey, you could be writing data now" -- "I don't have data to write"
  ...

at 100% CPU usage. Somehow you have to indicate to Gambas that you have
data to write and care about Write events being delivered for the time
it takes you to send that data. If you have no data to write, it would
be a tremendous waste of CPU cycles to alert you whenever the write
buffer of every one of your sockets is empty.

> If I have a global buffer declared and then defined with a huge amount of
> data to be sent over the socket, how do I use the Write event to write small
> chunks of that data to the socket if the Write event doesn't fire until I
> write to the socket?? Seems like a catch 22.
> 
> Would one write the first chunk in, say, the Socket_Read event handler and
> then let the Write event handle the rest? Sort of like priming a While loop?
> 

Yes, you have to kick off the process with an initial Write and then
subsequent Write events will be raised for you as soon as the socket
has more capacity to take in your data, for as long as you write more
data inside each event.

In an HTTP response it'd make sense to push the HTTP header into the
stream as an initial write, and then fetch and send the body in small
chunks, maybe from disk if you serve a static file. That'd be most
memory-efficient.

Maybe it would be good if Socket had an asynchronous version of Begin(),
which kicks the Write event machinery off instead, so that you can keep
all your Writes in the same place?

> > > Private crlf As String = Chr(13) & Chr(10)
> > 
> > BTW that particular constant is built into Gambas as gb.CrLf.
> 
> I thought something like that might be defined. I found gb.NewLine in "Predefined Constants" [0]. But, gb.CrLf is not there.
> 

Look again :-) I just added it.

If you're satisfied with the explanation above, I'll try to compose
a better Socket_Write page, too.

Regards,
Tobi

-- 
"There's an old saying: Don't change anything... ever!" -- Mr. Monk


More information about the User mailing list