http://qs321.pair.com?node_id=546141

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

Wise Monks,

What is wront with this code?
use strict; use warnings; use IO::Socket; use Tk; $| = 1; my $server = IO::Socket::INET->new( LocalPort => 2345, Type => SOCK_STREAM, Reuse => 1, Listen => 10 ) or die "Error: $@\n"; $SIG{CHLD} = sub { exit }; my $entry = "start..."; my $wsk = \$entry; my $main = MainWindow->new( -title => 'Socket - listen', ); my $ent1 = $main->Label( -text => "I'm waitin on port 2345\n So, you tell me... +", )->pack(); my $ent2 = $main->Label( -text => $entry, )->pack(); my $child; my $guzik1 = $main->Button( -text => 'Exit', -command => sub { kill 9, $child; exit 0 }, )->pack( -side => 'bottom', ); $child = fork(); if ( $child == 0 ) { while ( my $client = $server->accept() ) { while ( defined( my $in = <$client> ) ) { print $in; #control $ent2->configure( -text => $in ); } } } MainLoop()
When I send something on 2345 port I get error:
Attempt to free non-existent shared string '_TK_RESULT_', Perl interpreter: 0x2d 2eba4 at C:\dyr-win\notes\socket_tk2.pl line 36, <GEN1> line 1.
Free to wrong pool 2d2dbb0 not 273d08 at C:\dyr-win\notes\socket_tk2.pl line 36, <GEN1> line 1.

System: WindowsXP,
Perl: v5.8.8 built for MSWin32-x86-multi-thread

thanks for help,

greetz, Uksza

Yes, smart people know that fat arrow autoquotes the left argument. But why should you require your code to be maintained by smart people?
Randal L. Schwartz, Perl hacker

Replies are listed 'Best First'.
Re: Tk, fork and ->configure
by gri6507 (Deacon) on Apr 28, 2006 at 00:01 UTC
    As a short answer, only one process at a time can write to Tk at a time. You have two. in other words, you must make sure that only one process does the GUI stuff, and the other does only work and no GUI stuff. For a longer explanation, take a look here 372499
Re: Tk, fork and ->configure
by zentara (Archbishop) on Apr 28, 2006 at 11:22 UTC
    Well you have 2 seperate processes after the fork. One process cannot talk to the other with some form of IPC.(Inter Process Communication).

    What do you want to do? If you just need a simple socket connection listening, you don't need to fork, just use a fileevent to read the socket. Although fileevent may be unreliable on Windows, it often works.

    #!/usr/bin/perl use strict; use warnings; use IO::Socket; use Tk; $|=1; $SIG{PIPE} = 'IGNORE'; my $listen = IO::Socket::INET->new( Proto => 'tcp', LocalPort => 7070, Listen => 1, Reuse => 1, ) or die "Can't create listen socket : $!\n"; my $mw = MainWindow->new(); my $text = $mw->Scrolled('Text', -background =>'black', -foreground => 'yellow', )->pack(); my $subframe = $mw->Frame()->pack(); $subframe->Button(-text => 'Clear', -command => sub { $text->delete('1.0','end'); })->pack(-side=>'left'); $subframe->Button(-text => 'Save Log', -command => sub { })->pack(-side=>'left'); $subframe->Button(-text => 'Exit', -command => sub { exit })->pack(-side=>'right'); $mw->fileevent($listen, 'readable', sub { new_connection($listen) }); Tk::MainLoop; sub new_connection { my ($listen) = @_; my $client = $listen->accept() or warn "Can't accept connection"; $client->autoflush(1); $mw->fileevent($client, 'readable', sub { handle_connection($clien +t) }); #$client->print("Connected\n"); $text->insert('end', "Connected\t"); $text->see('end'); } sub handle_connection { my ($client) = @_; my $message = <$client>; if (defined $message and $message !~ /^quit/) { $message =~ s/[\r\n]+$//; #$client->print("Got message [$message]\n"); #echo back if wanted $text->insert('end', "Got message [$message]\t"); $text->see('end'); } else { $text->insert('end', "Connection Closed\n"); $text->see('end'); $client->close(); } }

    I'm not really a human, but I play one on earth. flash japh
Re: Tk, fork and ->configure
by BrowserUk (Patriarch) on Apr 28, 2006 at 12:07 UTC

    With the following minimal modifications to your code, it works.

    I wouldn't advise using it as is particularly but if you can understand how the modifications make it work, you'll probably see a better way for doing this. (Hint: You won't need fork)

    use strict; use warnings; use IO::Socket; use threads; use threads::shared; use Thread::Queue; use Tk; $| = 1; my $Q = new Thread::Queue; $Q->enqueue( 'Primer' ); my $server = IO::Socket::INET->new( LocalPort => 2345, Type => SOCK_STREAM, Reuse => 1, Listen => 10 ) or die "Error: $@\n"; $SIG{CHLD} = sub { exit }; my $entry = "start..."; my $wsk = \$entry; my $main = MainWindow->new( -title => 'Socket - listen', ); my $ent1 = $main->Label( -text => "I'm waitin on port 2345\n So, you tell me...", )->pack(); my $ent2 = $main->Label( -text => $entry, )->pack(); $main->repeat( 100, sub{ return unless $Q->pending; my $in = $Q->dequeue(); $ent2->configure( -text => $in ); } ); my $child; my $guzik1 = $main->Button( -text => 'Exit', -command => sub { kill 9, $child; exit 0 }, )->pack( -side => 'bottom', ); $child = fork(); if ( $child == 0 ) { while ( my $client = $server->accept() ) { while ( defined( my $in = <$client> ) ) { #print $in; #control $Q->enqueue( $in ); } } } MainLoop()

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.