in reply to endless loops for server and tk

Write 3 simple applications.

  1. Just sends every 5 seconds.
  2. Just receives and does what it needs to do.
  3. The Tk application that draws what you want to appear.

Test them individually.

When you are satisfied with them. come back, post the code and we can show you how easy it is to put the code from the each of the first two into its own thread, share whatever needs sharing and viola, you have your integrated application.


Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
"Too many [] have been sedated by an oppressive environment of political correctness and risk aversion."

Replies are listed 'Best First'.
Re^2: endless loops for server and tk
by hudo (Novice) on Aug 10, 2007 at 03:35 UTC
    Hello, I'll post some code that I have at the moment.
    The server accepting requests and responding immediately to the clients is here Normally the server reads from a mysql table and compares the request content to the table content, and updates eventually the mysql table.
    This is at the moment comment.
    The code for the client sending request after n seconds is here In the client I tried to let him receive the server-response with a timeout, but I did not succeed. Maybe some hints ? The client should continue to send every n seconds a request even if there is no server listening.
    By the way, when using the client on a xp machine it stops at the first time he receives (server is listening) when the server includes $startzeit in his response.
    If the client runs on ubuntu (vmware guest system) he receives the whole response if the response does not include $startzeit, but with the server code $sock->send("Zeitstempel: $startzeit : Du sagtest: ''$nachricht'' zu mir $/"); or   $sock->send("Zeitstempel: ''$startzeit'' : Du sagtest: ''$nachricht'' zu mir $/"); the client receives not the whole response or at least prints not the whole response to STDOUT. What could be here the problem ?

    Here is the actual contents of meinfile.txt which corresponds to the request:

    A first Tk code is here: If I edit the contents of the meinfile.txt in an editor, the changes are displayed immediately in the listbox.
    The listbox should later display the data of the mysql table which should be updated depending on the clients requests.

    vkon, I tried to implement the Tk code with fileevent, but I did not succeed. Here is my code:

    BrowserUk, the client code could be used as the server "just sending every 5 seconds".
    By the way, how could this be implemented,that the server listens to all UDP ports, not only to a specific. Later there are e.g. 5 clients, each sending on his on port (e.g. from 10001 to 10005) and the server should listen to all of these ports simultaneously, thats why I thought of listening to all UDP ports.

      Okay. Here are three separate minimal programs, and one composite that joins them all together. I have used your Tk program, cleaned up a lot. Sorry that your comments are missing, but I don't read Gernman and they were just in the way of seeing what was going on. You should really try to be a little more consistant with your code layout also.

      This is the standalone server that listens and responds to 5 different udp ports:

      #! perl -slw use strict; use IO::Socket::INET; use threads; my $noBlock = 1; ## Create an array of udp listeners my @listeners = map{ my $listener = IO::Socket::INET->new( LocalPort => $_, Proto => 'udp', Reuse => 1, ## Blocking => 0, ## No apparent effect on Win32. ) or die $!, $^E; ioctl( $listener, 0x8004667e, \$noBlock ); ## non-blocking on Win3 +2 $listener; } 10001 .. 10005; ## forever, but not too fast while( sleep 1 ) { my( $msg, $client ); ## iterate the listening ports for( 0 .. $#listeners ) { ## Read anything they have available ## Should check if there is more $client = $listeners[ $_ ]->recv( $msg, 1024, 0 ) ## and skip on if nothing there or warn "Nothing from $_\n" and next; ## Work out who's talking to us my( $port, $x ) = sockaddr_in( $client ); my $ip = inet_ntoa( $x ); ## And do **WHATEVER** with their message. print "$ip:$port : $msg" } }

      And this is the standalone client. It talks to all of the ports on the server for testing and demo, but would normally only talk to one. When used as the heartbeat thread withing the combined app, it would also talk to all 5 clients.

      #! perl -slw use strict; use IO::Socket; use constant { HEARTBEAT => 1, ## seconds AREYOUTHERE => 'Er, hello?', IPS => [ map{ scalar sockaddr_in( $_, inet_aton( '127.0.0.1' ) ) } 10001..10005 ], }; my $s = IO::Socket::INET->new( Proto => 'udp' ) or die $!, $^E; ## Forever, slowly until time to die while( sleep HEARTBEAT ) { for my $client ( 0 .. $#{ IPS() } ) { $s->send( "$client: " . AREYOUTHERE, 0, IPS->[ $client ] ) } }

      And here is my cleaned up and working version of your Tk code. I am posting it separately because you should maintain all 3 standalone apps as testbeds and reference points, as well as the combined app. It is much easier to test changes in the individual apps and, once you are satisfied they are working, c&p the changes into the combined app. It make seem extra work, but think of the separate apps and testcases.

      #!/usr/bin/perl use Tk; use Tie::File; my $liste; my $liste_font; my $breite=100; my $the_selectmode = "extended"; my $enter; my @array_file; my $mw = MainWindow->new(); my $frame1 = $mw->Frame( -width=>50, -height=>50, -bg=>"seashell" ); my $frame2 = $mw->Frame( -width=>5, -height=>5, -bg=>"grey80" ); $liste_font = $mw->fontCreate(-family=>"courier", -size=>7 ); my $liste = $frame1->ScrlListbox( -setgrid=>1, -scrollbars=>"se", -background=>"lemonchiffon3", -borderwidth=>3, -highlightthickness=>10, -height => 30, -selectforeground=>"blue", -selectbackground=>"green", -relief=>"ridge", -exportselection => 1 )->pack(-side=>"right", -expand=>1, -fill=>"both"); my $exitButton = $frame2->Button( -text=>"Schliessen" ,- command=>"exit" , -bg=>"red" , -activebackground=>"red", -activeforeground=>"cyan" )->pack( -anchor=>"w", -padx=>10 , -pady=>15 , -ipady=>10, -fill=>"x" ); $frame1->pack(-side => 'left' ,-expand=>1 ,-fill=>"both"); $frame2->pack(-side => 'right',-expand=>1 ); $frame2->pack(-expand=>1 ,-fill=>"both"); $mw->repeat(10, \&fill_with_tie ); MainLoop; sub fill_from_file { my $file = "meinfile.txt"; my $line; $liste->delete(0,"end"); if ( -s $file ) { open(DATEI, "<$file") or die $!; while ($line = <DATEI>) { chomp $line; $liste->insert(0,$line); } close(DATEI); } } sub fill_with_tie { my $file = "meinfile.txt"; my $line; my $elem; $liste->delete(0,"end"); if ( -e $file ) { tie @array_file, "Tie::File", $file || die $!; foreach $elem (@array_file) { chomp $elem; $liste->insert(0,$elem); } untie @array_file; } else { print "Kann $file nicht oeffnen $!\n"; } }

      And finally, the combined, threaded app. The modifications are minimal. Each thread is a direct C&P from the standalone version.

      In particular, there is very little shared data, as it is not clear what else you want to do or what else you need to share, but it should give you a starting point. My purpose is to demonstrate the simplicity of combining the code.

      After that, you are responsible for adding whatever extras you need. I'm willing to help you make your additions, but please don't post reams and reams of code with huge chunks commented out and reams and reams of comments that I cannot understand--just delete them from the post--otherwise I am apt to be put off.

      #!/usr/bin/perl use threads; use threads::shared; my $die :shared = 0; sub server { ## require IO::Socket; IO::Socket->import( qw[ :DEFAULT :crlf ] ); ## This attempts to defer the use until runtime ## and so limit the scope of the imports ## I'm not sure if it actually works. ## require would be better, but getting the imports ## to happen after the require doesn't always seem to work. ## Maybe someone watching can tell me how it should be done? eval { use IO::Socket::INET qw[ :DEFAULT :crlf ]; }; local $/ = CRLF; my $noBlock = 1; ## Create an array of udp listeners my @listeners = map{ my $listener = IO::Socket::INET->new( LocalPort => $_, Proto => 'udp', Reuse => 1, ## Blocking => 0, ## No apparent effect on Win32. ) or die $!, $^E; ioctl( $listener, 0x8004667e, \$noBlock ); ## non-blocking on +Win32 $listener; } 10001 .. 10005; ## forever, but not too fast while( sleep 1 and not $die ) { my( $msg, $client ); ## iterate the listening ports for( 0 .. $#listeners ) { ## Read anything they have available ## Should check if there is more $client = $listeners[ $_ ]->recv( $msg, 1024, 0 ) ## and skip on if nothing there or warn "Nothing from $_\n" and next; ## Work out who's talking to us my( $port, $x ) = sockaddr_in( $client ); my $ip = inet_ntoa( $x ); ## And do *WHATEVER* with their message. print "$ip:$port : $msg" . CRLF; } } } sub heartbeat { ## require IO::Socket; IO::Socket->import( qw[ :DEFAULT :crlf ] ); eval{ use IO::Socket qw[ :DEFAULT :crlf ]; }; local $/ = CRLF; use constant { HEARTBEAT => 5, ## seconds AREYOUTHERE => 'Er, hello?', ## You would vary the ips, ratehr than the ports here. ## I have it talking back to itself for demo purposes. IPS => [ map{ scalar sockaddr_in( $_, inet_aton( '127.0.0.1' ) ) } 10001..10005 ], }; my $s = IO::Socket::INET->new( Proto => 'udp' ) or die $!, $^E; ## Forever, slowly until time to die while( sleep HEARTBEAT and not $die ) { for my $client ( 0 .. $#{ IPS() } ) { $s->send( "$client: " . AREYOUTHERE, 0, IPS->[ $client ] ) } } } ## start the threads. my $server = async \&server; my $heartbeat = async \&heartbeat; ## Require Tk so it doesn't get loaded into the threads above. require Tk; Tk->import; require Tie::File; my $liste_font; my $breite=100; my $the_selectmode = "extended"; my $enter; my @array_file; my $mw = MainWindow->new(); my $frame1 = $mw->Frame( -width=>50, -height=>50, -bg=>"seashell" ); my $frame2 = $mw->Frame( -width=>5, -height=>5, -bg=>"grey80" ); $liste_font = $mw->fontCreate(-family=>"courier", -size=>7 ); my $liste = $frame1->ScrlListbox( -setgrid=>1, -scrollbars=>"se", -background=>"lemonchiffon3", -borderwidth=>3, -highlightthickness=>10, -height => 30, -selectforeground=>"blue", -selectbackground=>"green", -relief=>"ridge", -exportselection => 1 )->pack(-side=>"right", -expand=>1, -fill=>"both"); my $exitButton = $frame2->Button( -text=>"Schliessen" ,- command=> sub { ## Clean up the threads $die = 1; ## Tell them to commit hari kari $_->join for $heartbeat, $server; ## And wait tile they do exit; }, -bg=>"red" , -activebackground=>"red", -activeforeground=>"cyan" )->pack( -anchor=>"w", -padx=>10 , -pady=>15 , -ipady=>10, -fill=>"x" ); $frame1->pack(-side => 'left' ,-expand=>1 ,-fill=>"both"); $frame2->pack(-side => 'right',-expand=>1 ); $frame2->pack(-expand=>1 ,-fill=>"both"); $mw->repeat(10, \&fill_with_tie ); ## Use the class method as the sub was not imported because we require +d Tk. $mw ->MainLoop; sub fill_from_file { my $file = "meinfile.txt"; my $line; $liste->delete(0,"end"); if ( -s $file ) { open(DATEI, "<$file") or die $!; while ($line = <DATEI>) { chomp $line; $liste->insert(0,$line); } close(DATEI); } } sub fill_with_tie { my $file = "meinfile.txt"; my $line; my $elem; $liste->delete(0,"end"); if ( -e $file ) { tie @array_file, "Tie::File", $file || die $!; foreach $elem (@array_file) { chomp $elem; $liste->insert(0,$elem); } untie @array_file; } else { print "Kann $file nicht oeffnen $!\n"; } }

      To answer your question from Re^2: Displaying text in columns, I've used spoiler tags, rather than readmore tags, despite this usage being frowned upon, because spoiler tags do not get expanded until you choose to click on them whereas readmore tags are expanded whenever you view the post directly. This way, you can read the text of the post as a coherent whole without having to scroll past loads of code.


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.