I'm trying to work through a small Perl learning project that requires reading 4 unsigned integers from a socket. I couldn't get more than 1 integer read, and after digging around I found a solution. But I NEED to understand what I didn't do right (and have gone through a couple of Perl books, perldocs, etc to no avail.)
Example 1: Here's the successful solution code (original), assume the socket connect is successful for both below:
{
local $/ = \16; # make <> read in 16 bytes with one swoop.
my @integers = unpack "IIII", <$sock>;
print "numbers: @val\n";
}
Example 2: I tried this below. If I print the input prior to unpacking, I only get one Integer:
my $input;
$sock->recv($input,16,0);
my @integers = unpack("IIII", $input);
Specific questions:
Any help, pointers, etc. is appreciated. Btw, the "learning project" is overthewire.org - pretty cool stuff.
If successful, recv() returns the length of the message or datagram in bytes. The value 0 indicates the connection is closed.
The recv() call receives data on a socket with descriptor socket and stores it in a buffer. The recv() call applies only to connected sockets. This call returns the length of the incoming message or data.
The recv function is used to read incoming data on connection-oriented sockets, or connectionless sockets. When using a connection-oriented protocol, the sockets must be connected before calling recv. When using a connectionless protocol, the sockets must be bound before calling recv.
recv(IPC, Buffer, int n) is a blocking call, that is, if data is available it writes it to the buffer and immediately returns true, and if no data is available it waits for at least n seconds to receive any data.
Is your socket TCP or UDP?
recv
is a lower-level routine than <>
/ readline
. It maps more or less directly to the recv(2)
system call. If the socket data is arriving as 4 4-byte packets, recv
will return immediately once it sees the first packet even if it has been supplied a larger buffer. If all 4 packets arrive before the first call to recv()
, then whether you get all the data or just one piece likely depends on whether it is TCP or UDP.
If you are using TCP, there's a possibility that packets will be fragmented in flight. It's unlikely to happen with 16 byte payloads, but best practice would be not to assume that 16 bytes of data will show up all at once even if you know the server sent it all at once. Network applications are generally expected to buffer the incoming data, or, you can have perl do it for you by specifying 16-byte records with $/ = \16
.
Another possibility, which I find more natural than <>
for this kind of I/O usage, is to use the read
or sysread
functions (or the OO equivalents, which are defined in the IO::Socket
superclass IO::Handle
). Those take a length argument, but as before, you should not assume that the entire buffer will be filled at once.
As for 1)
Well, <>
takes any filehandles, including sockets. It is a convention that you can leave it empty, in which case a some kind of sane default behaviour is assumed. See perldoc perlop
(search for <>
inside).
And special variable $/
is record separator and it defaults to "\n". You can undef it and read the whole file at once (that's called slurping). See perldoc perlvar
for more (the \number
case is also there).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With