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

Hi Monks,

I have a problem that I would really appreciate your help with. I am running POE to spider websites, one session is created per URL in an array that is fed to the program.

My issue is that I am receiving the error print() on closed filehandle occasionally. I was receiving it everytime untilI changed the name of the session filehandle to match the current session ID (my $id = $_SESSION->ID;).

The code is largely straight out of the cookbook.

Despite using the session ID, I still get filehandle errors. Is there a better way to manage filehandles to avoid this happening?


Many thanks in advance,
PC

Replies are listed 'Best First'.
Re: Print() on closed filehandle POE
by rcaputo (Chaplain) on Nov 02, 2010 at 00:50 UTC

    Generally speaking, vague questions can at best garner vague answers. Your current question is virtually unanswerable as it stands for at least three reasons.

    • "Largely straight out of the cookbook" implies you've made changes. We need to see the actual running code to diagnose a problem.
    • Even if you used an example directly from the cookbook, the page you've cited contains three of them. If you're using a particular piece of code, tell us which so we can investigate.
    • It's anyone's guess what code is triggering the error. You didn't mention a file and line number.

    If you come over to irc.perl.org channel #poe while we're awake, we can work through this with less latency.

      Many thanks for the feedback guys, I'd really appreciate some help with this - the script works fine apart from the closed filehandle error. As mentioned before, I'm assigning the current session name as the filehandle for printing, which I thought would be unique but I might have misunderstood the POE code. Here it is:

      #!/usr/bin/perl use warnings; use utf8; #use strict; use LWP::UserAgent; use HTTP::Request::Common qw(GET POST); use POE qw(Component::Client::HTTP); #capture the search term print "Welcome, please enter your search term: \n"; chomp (my $term = <>); my @url_list=(); if ($term){ my $browser = LWP::UserAgent->new; $browser->agent('Mozilla/6.0'); #post the search query to Scroogle my $response = $browser->post( 'http://www.scroogle.org/cgi-bin/nbbw.cgi', ['Gw'=>$term, 'n'=>'1', 'l'=>'en']); # set the volume and language of +the returned pages #build a list of returned links if($response->is_success){ $response = $response->decoded_content; @url_list = ($response =~ / href="(http:.*?)"/g); %urls=(); my $count =1; foreach (@url_list){ $urls{ $_ } = $count; $count++; } } } #Setup the virtual browser and its configuration POE::Component::Client::HTTP->spawn( Alias => 'Mozilla', #alias of the url request to the web server MaxSize => 300000, # Set the maximum HTML page size you want to r +etrieve. Timeout => 20, #this is the number of seconds to wait before canc +elling retrieval ); # Create a session for every URL taken from the search. foreach my $url (@url_list) { POE::Session->create( inline_states => { _start => sub { my ($kernel, $heap) = @_[KERNEL, HEAP]; # Post a request to the HTTP user agent component. When the # component has an answer (positive or negative), it will # send back a "got_response" event with an HTTP::Response # object. $kernel->post(Mozilla => request => got_response => GET $url ) +; }, # A response has arrived. Display it. got_response => sub { my $id = $_[SESSION]->ID; my $filehandle = $id; my ($heap, $request_packet, $response_packet) = @_[HEAP, ARG0, + ARG1]; # The original HTTP::Request object. If several requests # were made, this can help match the response back to its # request. my $http_request = $request_packet->[0]; # The HTTP::Response object. my $http_response = $response_packet->[0]; # Make the response presentable, and display it. my $response_string = $http_response->decoded_content(); $response_string=~ s/[[:^ascii:]]/ /g; #removes non ASCII char +acters $response_string =~ /<title>(.*?)</; #captures the webpage tit +le my $rank = $urls{$url}; if ($1){ my $title = $1; $response_string =~ s/<(?:[^>'"]*|(['"]).*?\1)*>//gs; #removes + the HTML #$response_string =~s/[^a-zA-Z]|\D|[^\.'\-\$]/ /g; #replaces n +on character text with whitespace my @paragraphs = split /\n/, $response_string; #this splits up + every paragraph in the remaining text my @results; foreach (@paragraphs){ if (/ $term /){ unshift(@results, $_); } } if (@results){ print "Content for $term found at $url\n"; open ($filehandle,">>:utf8", "c:/perl/results/$title.txt"); #c +reates a new file print $filehandle "$url\n$rank\n"; #prints URL and search eng +ine ranking to the file foreach (@results){ print $filehandle "$_\n"; } close $filehandle; } else{ print "No relevant text found at $url\n"; } } }, }, ); } # Run everything, and exit when it's all done. $poe_kernel->run(); exit 0;

        I changed the scalar used for the filehandle to a unique global array element ($rank), and changed the to-be created filename to a simpler scalar ($rank . $term). This fixed the issue and now it works great...except scroogle went down today :( .

Re: Print() on closed filehandle POE
by umasuresh (Hermit) on Nov 02, 2010 at 12:42 UTC
    Most likely you did not open it to begin with, check if you have this:
    open (POE, '> output_file') || die "can't open the output file $!\n"; ... ... close POE;