问题
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:
- In example 1, what the heck is "$/"? And how does it "change" <>, which I thought read STDIN?
- In example 2, is there some reason why my recv() doesn't take more than one integer off the socket? My understanding (per perldoc) is that the "SIZE" parameter defaults to "bytes", and integers are 4 bytes?
Any help, pointers, etc. is appreciated. Btw, the "learning project" is overthewire.org - pretty cool stuff.
回答1:
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).
回答2:
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.
回答3:
read
and readline
(aka <>
) wait for the requested amount of chars to be available before returning. It will only return fewer characters in the event of an error or EOF, in which case the next read will return an error or EOF.
sysread
returns as soon as some characters are available, even if there are fewer than the requested amount.
Based on what you're saying, recv
is like sysread
. If you want 16 characters, you'll have to loop until you have 16 characters or use read
or readline
.
来源:https://stackoverflow.com/questions/5599585/socket-recv-vs