Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

socket reading...

by jdv79 (Sexton)
on Jul 28, 2001 at 00:16 UTC ( #100440=perlquestion: print w/replies, xml ) Need Help??

jdv79 has asked for the wisdom of the Perl Monks concerning the following question:

I am trying to write a simple, at least what I thought was going to be, TCP client to talk a piece of telco equipment to do provisioning via a CGI frontend(because I am NOT going to be responsible for teaching 20 guys the TL1 command language). In short I am having trouble terminating my read on the socket after I issue commands. I see in alot of the docs to use while(defined($line = <$sock>)) or @lines = <$sock>. Thats doesn't seem to work. I tried using select and that hangs as well. How would I be able to terminate a read fromthe socket when the last line of data comes in? Is there a way to do this without matching a string? I seem to be losing the last characeter in my responses as well, or the last line. The command prompt on this system is a ";" and I never see it in the STDOUT stream but I do see it if I sniff the session. heres the code:
#!/usr/bin/perl -w use IO::Socket; use IO::Select; use strict; ##INITIALIZE VARS## my $host = ($ARGV[0] || 'localhost'); my $port = ($ARGV[1] || '5501'); my $cmd1 = "act-user::dacsmaster:jdv::passwd;\n"; my $cmd2 = "rtrv-crs-t1::all:jdv;\n"; ##CREATE SOCKET## my $sock = IO::Socket::INET->new(PeerAddr => "$host", PeerPort => "$port", Proto => 'tcp', Type => SOCK_STREAM ); die "Socket could not be created. Reason: $!\n" unless $sock; $sock->autoflush(1); ##WRITE TO SOCKET## my $length = length($cmd1); syswrite($sock,$cmd1,$length); ##READ FROM SOCKET## my $read = ''; # Initialise to an empty set # (NOTE: $read=0 is very wrong) vec($read, fileno($sock), 1) = 1; # Set the appropriate bit #vec($read, fileno(FILE2), 1) = 1; # And for another file... for(;;) { my $found = select($read, undef, undef, undef); print "while loop ran\n"; # Does FILE1 have data waiting? if (vec($read,fileno($sock), 1)) { sysread($sock,my $line,1024); print "LINE:"."$line\n"; } else { print "nothing to read\n!"; last; } } print "after for loop\n"; ##CLOSE SOCKET AND EXIT## close($sock) || die "$!"; exit;

Replies are listed 'Best First'.
Re: socket reading...
by wog (Curate) on Jul 28, 2001 at 00:56 UTC
    Your problem could probably be fixed by placing the socket in non-blocking mode. When in non-blocking mode it is gaurenteed that your process will not block from operations on the socket. However, this means that you should check the return values of all your reads (and writes, maybe) in case they return an error ( for when blocking would have occured, EAGAIN ("Resource temporarily unavailable" (but locale can change that message)); the Errno module will be helpful.) You can turn blocking off with:

    $sock->blocking(0);

    Note that IO::Select provides an alternate select interface that you aren't using. You do not need to use a module to use the built-in select interface.

    Note that when sysread returns 0 that means EOF.

      I tried using your $sock->blocking(0); and it produced this: Can't locate auto/IO/Socket/INET/blocking.al in @INC (@INC contains: /usr/lib5 I am not familiar with .al
      Thanks alot for your help!
        This appears to indicate that your installation of the IO::Socket::INET module (which comes with perl since perl version 5.004) is somehow curropted. It appears to indicate that AutoLoader was used for IO::Socket::INET, something which oddly I don't find evidence of in versions of perl I have access to (5.005_02, 5.6.0, 5.7.1@11471). It also seems to indicate that a file that was supposed to have been created by AutoSplit during installation cannot be found.
Re: socket reading...
by Moonie (Friar) on Jul 28, 2001 at 01:20 UTC
    You may want to read up on using timeout with the select() function. But definately read up on non-blocking. Here's a pretty good reference (Unix wise): Unix Socket FAQ
Re: socket reading...
by traveler (Parson) on Jul 28, 2001 at 01:45 UTC
    If the TCP server is keeping the connection open (that is, not doing a C close(2) on the socket) and if the server does not set the PSH (push) bit on the TCP segments containing the newlines, the last portion of data may not make it to your application for some time.

    If you control the application server, you can likely control the first aspect: closing the socket. You may or may not be able to cause the PSH bit to be set.

    As wog noted, sysread returns 0 (the number of bytes read) on EOF, but it is only EOF iff the socket is closed by the server.

    --traveler

      The problem with that is that the TCP server is a relaitvely dumb host and does not have the ability to close the socket. My client has to do that. From what I am hearing and what I have been trying since my initial post is that the best way to exit the recieve stream read would be to match on the prompt even though I cant see it from the client. This presents a slight issue.
        You could try to send some sort of a NOP (e.g. just an empty request or newline equivalent). That might force the server to send out some more data (e.g. prompts) causing your client host to flush the buffer to the application. Enough NOP packets might get you a prompt to your app. You'd have to skip empty prompts on the next read if they are not all delivered to your application.
Re: socket reading...
by bikeNomad (Priest) on Jul 28, 2001 at 21:09 UTC
    You could put your socket into non-blocking mode and actually look at the return value from sysread. If your responses over the socket are record-oriented and terminated by a particular character (like, say, "\n") you could set $/ to that character and use the <$sock> form. Otherwise, if you have a length indication at the beginning of each response, read that first and then read exactly the right number of bytes.

    update: corrected part about blocking if you try to read too many bytes.

      I don't agree with this assumption:

      When select comes back to you it means that some data is available; it doesn't say how much. Then you try to read 1024 bytes. If there isn't that much data available, and you're in blocking mode, it'll try to wait.

      read() and/or sysread() will read whatever is there without waiting on the remainder of the 1024 bytes. They will block if there's no data to read, but select() says there is data.

Re: socket reading...
by petral (Curate) on Jul 29, 2001 at 19:11 UTC
    BTW, don't you have to reload the $read vec after each select?

      p

      please explain, if you will.
        from perlfunc select (second select entry :) )

              The usual idiom is:
        ($nfound,$timeleft) = select($rout=$rin, $wout=$win, $eout=$ein, $timeout);
        select overwrites $rout (your $read) to indicate what's available. So, except in the simplist case (1 fd, quit when done, like your example), it needs to be reset to the original on each call. You would need to if, for instance, you uncomment your vec(...FILE2) line.

          p

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://100440]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others contemplating the Monastery: (4)
As of 2021-06-17 21:33 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    What does the "s" stand for in "perls"? (Whence perls)












    Results (85 votes). Check out past polls.

    Notices?