perl socket not flushed on shutdown

The following code fails, even if you have the echo server running:

#!/usr/bin/perl -w
 use strict;
 use Socket;

($remote, $port, $serv, $iaddr, $paddr, $proto_name, $proto, 
$line, $an_ix, $loop_count, $do_shutdown);

# configuration

$loop_count = 01000;	# set to 010000 to succeed
$do_shutdown = 01;	# otherwise the programme will wait indefinitely

$proto_name = 'tcp';
($proto = getprotobyname ($proto_name)) || die "$proto_name: $!";
$remote = 'localhost';
($iaddr = inet_aton ($remote)) || die "$remote: $!";
$serv = 'echo';
($port = getservbyname ($serv, 'tcp')) || die "$serv: $!";
socket (SOCK, PF_INET, SOCK_STREAM, $proto) || die "socket: $!"; 
connect SOCK, sockaddr_in ($port, $iaddr) || die "connect: $!"; 
for ($an_ix = 0; $an_ix < $loop_count; ++$an_ix) { print SOCK 'a'; print '+'; } 
shutdown SOCK, 01 if $do_shutdown; read (SOCK, $line, 01) >= 0 || die "read: $!"; 
die "fail: expected 'a', got '$line'" unless $line eq 'a';
close SOCK;

The reason is that shutdown does not flush the file handle representing the socket. Which is not what one would expect.

What do you think?

You’re mixing buffered and unbuffered I/O. print is buffered but read is raw. You should set autoflush on the socket or use syswrite instead of print.

But what if I would rather use a buffered socket? I have a protocol that allows buffering.

Then you should call flush on the socket before closing it. You should also call flush when completed lines are expected.

It is rather inconsistent. If I call close, the buffer is flushed, but if I call shutdown, it is discarded.
But if I call close on a socket, it is closed both ways so I shall not be able to read the answer.
Thanks anyway :slight_smile:

shutdown’s flush has nothing to do with buffered I/O. It works at the socket level. shutdown just maps to the shutdown system call. Your bytes are stuck in the I/O buffer. Perl’s close will also flush the buffered I/O. It’s more than just the close system call.

You have to differentiate between library routines and syscalls.