What does autoflush do in socket? why do we use it?

8.6k Views Asked by At

I am working on some socket code and unable to figure out why there is autoflush used on socket. It is something like this

my $sock = IO::Socket::Unix(Peer => $socketfilename , Type => SOCK_STREAM)

autoflush $sock 1;

Also there are places with

autoflush STDERR 1

autoflush STDOUT 1

for general filehnadles.

What does it do? Also what happens or will happen if I don't use it? Please give some practical example so that I will understand rather than simple definition.

3

There are 3 best solutions below

1
On

Data doesn't usually get sent right away on the socket, it is buffered up to a certain point and then sent all-at-once.

Auto-flushing means data goes right through the buffer and then flushed out, not kept in the buffer waiting for other data to arrive and accumulate.

As simple as that.

Without auto-flush:

Tick | DATA sent|Socket Buffer| DATA received
.....|..........|.............|..............
1    | XX       | XX          | (nothing)
2    | yy       | yyXX        | (nothing)
3    | ZZZ      | ZZZyyXX     | (nothing)
4    | t        | (empty)     | tZZZyyXX

With auto-flush:

Tick | DATA sent | Socket Buffer | DATA received
.....|...........|...............|..............
1    | XX        | ()            | XX
2    | yy        | ()            | yy
3    | ZZZ       | ()            | ZZZ
4    | t         | ()            | t
  • Socket Buffer size: 8 chars
  • Very simple example, you might raise some other questions after seeing it - a big part of it is also implementation-dependent. Moreover, buffering can happen at various levels (sender, receiver, application, etc.. )
1
On

From IO::Handle:

sub autoflush {
    my $old = new SelectSaver qualify($_[0], caller);
    my $prev = $|;
    $| = @_ > 1 ? $_[1] : 1;
    $prev;
}

No magic.

from :

$|

If set to nonzero, forces a flush right away and after every write or print on the currently selected output channel. Default is 0 (regardless of whether the channel is really buffered by the system or not; $| tells you only whether you've asked Perl explicitly to flush after each write). STDOUT will typically be line buffered if output is to the terminal and block buffered otherwise. Setting this variable is useful primarily when you are outputting to a pipe or socket, such as when you are running a Perl program under rsh and want to see the output as it's happening. This has no effect on input buffering. See getc for that. See select on how to select the output channel. See also IO::Handle.

1
On

It does absolutely nothing ...because IO::Socket::Unix already does it for you.

There's less overhead to send data in chunks, so file libraries accumulate data to print in a buffer instead of sending to the system immediately. Only when 4KB or 8KB (depending on the version) of data has been accumulated is the data actually sent to the system. This is called "buffering".

Setting autoflush to true for a handle disables buffering for that handle. When you call print, the data is sent to the system before print returns.

See the difference:

$ perl -e'
   STDOUT->autoflush($ARGV[0]);
   for (0..9) { print $_ x 1024; sleep 1; }
' 1
<whole bunch of 1s>
<one second later: whole bunch of 2s>
<one second later: whole bunch of 3s>
<one second later: whole bunch of 4s>
<one second later: whole bunch of 5s>
<one second later: whole bunch of 6s>
<one second later: whole bunch of 7s>
<one second later: whole bunch of 8s>
<one second later: whole bunch of 9s>

$ perl -e'
   STDOUT->autoflush($ARGV[0]);
   for (0..9) { print $_ x 1024; sleep 1; }
' 0
# Before Perl 5.14:
<four seconds later: whole bunch of 0s, 1s, 2s and 3s>
<four seconds later: whole bunch of 4s, 5s, 6s and 7s>
<two seconds later: whole bunch of 8s and 9s>
# Perl 5.14+
<eight seconds later: whole bunch of 0s, 1s, 2s, 3s, 4s, 5s, 6s and 7s>
<two seconds later: whole bunch of 8s and 9s>

autoflush is turned on by IO::Socket::* because it's needed most of the times for sockets. Sockets are often used for interactive communication. Request, reply, request, reply, etc. Imagine what would happen if the request was stuck in a buffer.... You'd be waiting for the reply forever!