socket->recv() vs. <>?

孤人 提交于 2019-12-10 13:18:43

问题


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:

  1. In example 1, what the heck is "$/"? And how does it "change" <>, which I thought read STDIN?
  2. 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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!