deadpickle has asked for the wisdom of the Perl Monks concerning the following question:
This program is used to transfer a file to a server and is written in perl/Tk. The idea of the file is to enter all the information and then hit the connect button. The button then says Stop which is suppost to end the sftp subroutine. The program then creates a thread and connects to the server and transfers the file repeatedly until the stop button is clicked. What I am having trouble in doing is once you click "Connect" the file should keep transfering until the user clicks the 'Stop" button. As of now the file only transfers once. If anyone has ideas on how to do this I would be eternally greatful.
#!/usr/bin/perl -w
use strict;
use warnings;
use Tk;
use Net::SFTP::Foreign;
use threads;
use threads::shared;
my $user = 'jlahowet';
my $server = 'mistral.unl.edu';
my $lcl = '/home/deadpickle/Desktop/Virtual Cockpit/';
my $rmt = '/home/jlahowet/UAV/COORDS/';
my$uav = 'uavposition';
my $mw = MainWindow->new();
my $go = 0;
my $monitor: shared;
$mw->configure(-title => 'VIRTUAL COCKPIT:SFTP', -background => 'blue'
+);
$mw->geometry('+400+300');
#User entry
my $usr = $mw->Frame(-relief => 'groove', -borderwidth => 3, -backgrou
+nd => 'blue')->pack(-side => 'top', -fill => 'x');
my $usrlbl = $usr->Label(-text => 'Username', -background => 'blue', -
+foreground => 'white')->pack(-side => 'left');
my $usreny = $usr->Entry(-width=> 10, -textvariable => \$user)->pack(-
+side => 'left', -pady => 3);
#Server entry
#my $svr = $mw->Frame(-relief => 'groove', -borderwidth => 3, -backgro
+und => 'blue')->pack(-side => 'top', -fill => 'x');
my $svrlbl = $usr->Label(-text => 'Server', -background => 'blue', -fo
+reground => 'white')->pack(-side => 'left');
my $svreny = $usr->Entry(-width=> 15, -textvariable => \$server)->pack
+(-side => 'left', -pady => 3);
#File locations
my $loc = $mw->Frame(-relief => 'groove', -borderwidth => 3, -backgrou
+nd => 'blue')->pack(-side => 'top', -fill => 'x');
my $uavlbl = $loc->Label(-text => 'UAV: ', -background => 'blue', -fo
+reground => 'white')->pack(-side => 'left');
my $filelbl = $loc->Label(-text => 'File', -background => 'blue', -for
+eground => 'white')->pack(-side => 'left');
my $fileeny = $loc->Entry(-width=> 8, -textvariable => \$uav)->pack(-s
+ide => 'left', -pady => 3);
my $lcllbl = $loc->Label(-text => 'Local', -background => 'blue', -for
+eground => 'white')->pack(-side => 'left');
my $lcleny = $loc->Entry(-width=> 25, -textvariable => \$lcl)->pack(-s
+ide => 'left', -pady => 3);
my $rmtlbl = $loc->Label(-text => 'Remote', -background => 'blue', -fo
+reground => 'white')->pack(-side => 'left');
my $rmteny = $loc->Entry(-width=> 25, -textvariable => \$rmt)->pack(-s
+ide => 'left', -pady => 3);
#Connect button
my @setup = ($user, $server, $lcl, $rmt, $uav);
my $btn = $mw->Button(-text => 'Connect', -background => 'gray', -comm
+and => \&sub1)->pack(-side => 'bottom', -padx => 3, -pady => 3, -anch
+or => 'e');
MainLoop;
sub sub1 {
if($btn->cget(-text) eq 'Connect'){
$go = 1;
$btn->configure(-text=> 'Stop');
my $thr = threads->new(\&sftp, @setup);
$monitor = 0;
}
else{
$go = 0;
$btn->configure(-text=> 'Connect');
$monitor = 1;
}
print "$go\n";
}
sub sftp {
my $host = $_[1];
my $usrname = $_[0];
my $port = 22;
my $seconds = 20;
my %args = (user=>$usrname, port=>$port, timeout=>$seconds);
my $local = $_[2];
my $remote = $_[3];
my $uavfile = $_[4];
my $sftp = Net::SFTP::Foreign->new($host, %args);
print $monitor;
eval {
$sftp->put("$local$uavfile", "$remote$uavfile",
callback => sub {
die "aborted" if $monitor; # $monitor
+has to be set from the other thread
})
};
if ($@ and $@ =~ /^aborted/) {
undef $sftp;
print "Stopped";
$monitor = 0;
}
sleep (2);
exit(1);
}
Re: Looping File transfer using SFTP in TK
by zentara (Archbishop) on Apr 10, 2007 at 18:21 UTC
|
You probably havn't seen it yet, but I answered you in comp.lang.perl.tk
I made a fake sftp client for testing, but you can uncomment
the real lines. Also, since you want to repeatedly send the same file, you didn't need the callback(unless you want to track large file progress).
#!/usr/bin/perl
use strict;
use warnings;
use Tk;
use Net::SFTP::Foreign;
use threads;
use threads::shared;
my $user = 'jlahowet';
my $server = 'mistral.unl.edu';
my $lcl = '/home/deadpickle/Desktop/Virtual Cockpit/uavposition';
my $rmt = '/home/jlahowet/UAV/COORDS/uavposition';
my $go:shared = 0;
#my $monitor:shared = 0;
my $die:shared = 0;
my $progress:shared = 0;
my @setup = ($user, $server, $lcl, $rmt);
#start thread before any Tk code
my $thr = threads->new(\&sftp, @setup);
#now setup Tk
my $mw = MainWindow->new();
$mw->protocol('WM_DELETE_WINDOW' => sub { &clean_exit });
$mw->configure(-title => 'VIRTUAL COCKPIT:SFTP', -background =>'blue')
+;
$mw->geometry('+400+300');
#User entry
my $usr = $mw->Frame(-relief => 'groove', -borderwidth => 3, -backgrou
+nd => 'blue')->pack(-side => 'top', -fill => 'x');
my $usrlbl = $usr->Label(-text => 'Username', -background => 'blue', -
+foreground => 'white')->pack(-side => 'left');
my $usreny = $usr->Entry(-width=> 10, -textvariable => \$user)->pack(-
+side => 'left', -pady => 3);
#Server entry
my $svr = $mw->Frame(-relief => 'groove', -borderwidth => 3, -backgrou
+nd => 'blue')->pack(-side => 'top', -fill => 'x');
my $svrlbl = $svr->Label(-text => 'Server', -background => 'blue', -fo
+reground => 'white')->pack(-side => 'left');
my $svreny = $svr->Entry(-width=> 15, -textvariable => \$server)->pack
+(-side => 'left', -pady => 3);
#File locations
my $loc = $mw->Frame(-relief => 'groove', -borderwidth => 3, -backgrou
+nd => 'blue')->pack(-side => 'top', -fill => 'x');
my $lcllbl = $loc->Label(-text => 'Local', -background => 'blue', -for
+eground => 'white')->pack(-side => 'left');
my $lcleny = $loc->Entry(-width=> 25, -textvariable => \$lcl)->pack(-s
+ide => 'left', -pady => 3);
my $rmtlbl = $loc->Label(-text => 'Remote', -background => 'blue', -fo
+reground => 'white')->pack(-side => 'left');
my $rmteny = $loc->Entry(-width=> 25, -textvariable => \$rmt)->pack(-s
+ide => 'left', -pady => 3);
#Connect button
my $btn = $mw->Button(-text => 'Connect',
-background => 'gray',
-command => \&sub1)
->pack(-side => 'bottom', -padx => 3, -pady => 3, -anchor => '
+e');
# to monitor file count, needs a timer to update
# from thread
my $val = 0;
my $label = $mw->Label(
-width => 50,
-textvariable => \$val )->pack(-side => 'bottom', -padx => 3,
+ -pady => 3, -anchor => 'w');
my $timer = $mw->repeat(10,sub{
$val = $progress;
});
MainLoop;
sub sub1 {
if($btn->cget(-text) eq 'Connect'){
$go = 1;
$btn->configure(-text=> 'Stop');
#$monitor = 0;
}
else{
$go = 0;
$btn->configure(-text=> 'Connect');
#$monitor = 1;
}
print "go = $go\n";
}
sub sftp{
$|++;
# setup your sftp connection
my $host = $_[1];
my $usrname = $_[0];
my $port = 22;
my $seconds = 20;
my %args = (user=>$usrname, port=>$port, timeout=>$seconds);
my $local = $_[2];
my $remote = $_[3];
# commented out to skip actual sftp use
# my $sftp = Net::SFTP::Foreign->new($host, %args);
my $sftp;
print "sftp connected\n";
#now go into a waiting loop, where you wait for
#$go to be 1
#when $go = 1, the sftp will keep sending the file
#the only way to break out is to set $die=1
while(1){
if($die == 1){ goto END };
# the go loop
if ( $go == 1 ){
for(;;){
# $sftp->put("$local", "$remote");
print "fake file being sent\n";
$progress++;
sleep 2;
if($go == 0){last}
if($die == 1){ goto END };
}
$go = 0; #turn off self before returning
}else { sleep 1 } # sleep if $go == 0
# end of go loop
} #end of while loop
END:
undef $sftp;
print "sftp stopped thread ending\n";
}
sub clean_exit{
$timer->cancel;
my @running_threads = threads->list;
if (scalar(@running_threads) < 1){print "\nFinished\n";exit}
else{
$die = 1;
$thr->join;
exit;
}
}
| [reply] [d/l] |
|
Thanks for the responses, they are very helpful. What I want is for the sftp to disconnect when the Stop button is pushed. that way the script allows the user to change the variables and run the transfer again.
Right now I am trying to understand how zentara's code works since it incorporates syntax I have never seen (and it seems to make it easier).
One problem is that the program connects right away not allowing the user to change the variables before it is connected to the server. I moved the SFTP connection to work only when $go = 1, that way it only connects of you push connect. But you cant change the variables like username from jlahowet to something else. It wont pass the new value to the thread for some reason, any help?
| [reply] |
|
Well to save you the head-scratching( I'm familiar with it due to hours of my own head-scratching :-) ), here is how to do it so each sftp run can be different.
| [reply] [d/l] |
|
|
|
Yeah, to make a new connection each run, move the connect to inside the go loop. To use new connection info for each connection, make them shared varaibles. Like:
my $user:shared = 'jlahowet';
+
my $server:shared = 'mistral.unl.edu';
+
my $lcl:shared = '/home/deadpickle/Desktop/Virtual Cockpit/uavposition
+';
my $rmt:shared = '/home/jlahowet/UAV/COORDS/uavposition';
#my $thr = threads->new(\&sftp, @setup);
my $thr = threads->new(\&sftp);
#then in your thread-code use the shared vars instead of
#using the passed in @setup array
You already have your entry widgets to setup to automatically change the vars with -textvariable.
There is one thing to watch out for: sometimes the threads
will not automatically pick up changes in textvariables, you might have to manually read them, but try it first, you may get lucky.
| [reply] [d/l] |
Re: Looping File transfer using SFTP in TK
by dana (Monk) on Apr 10, 2007 at 17:43 UTC
|
I may be missing it but your program seems to only refer to sub1 one time, within the main body of the program
my $btn = $mw->Button(-text => 'Connect', -background => 'gray', -comm
+and => \&sub1)->pack(-side => 'bottom', -padx => 3, -pady => 3, -anch
+or => 'e');
I think you want a call to sub1 in sftp (I may be missing it). The sftp needs a way to check if 'stop' has been pushed and if not repeat the sftp subroutine.
| [reply] [d/l] |
Re: Looping File transfer using SFTP in TK
by MonkE (Hermit) on Apr 10, 2007 at 17:35 UTC
|
You did say that you want to transfer the file "repeatedly", but I don't see any looping in your sftp sub ... or am I missing something? As soon as it completes one full transmission of the file, it will quit. The bit with the callback checking $monitor will halt the transmission in "mid put", but it will not send the file more than once. | [reply] |
|
|