Pinging a host only while SCP is present

Hello all,

I am doing some measurement tests on my network and I am writing a script to scp a file between two computers.

What I need to do is ping the receiving-computer while the SCP is running. Find below the portion of code which I have written so far.

Code:
      while ($scppresent == 1)
	if (`ps -ax | grep scp | wc -l | cut -c 8-12` > 1) then
	     ping -i 0.02 -s 504 $scpClient
	else
	    killall ping
	    set scppresent = 0
	endif
      end

The problem with this code is that multiple instances of ping will initiate every time the loop is checked. Any ideas on how I can avoid that? (that is have only one instance of ping running until the scp transfer is complete!)

Thanking you all for your time and help,

atwinix
 
Your code snippet suggests, you're not calling ping as a background process so it's quite unclear why "multiple instances" of ping can be run synchronous. From looking at the code snippet I would think your while loop should hang while ping is running.

On a side note, I would suggest to remove the ps + grep + wc + cut construct and replace it by a single pgrep(1) call (saves a lot of cpu time when being called in a loop as just one process needs to be spawned) and just check its return code.

My next suggestion would be to start scp in the background, remember it's PID, install a signal handler, then start ping in the background and whenever you're receiving a HUP signal, check if scp is still running and kill ping if scp finished.

Oh and from my experience, csh is a troublemaker for scripting (YMMV). I strongly avoid using this and instead use sh(1) for all scripting needs.

Other than these suggestions, I think we need to have a look at your complete script to suggest more.
 
Thanks for your input vwe@. I really appreciate it. I have only been scripting for a while now. I am starting scp in background. And I do understand most of the things you outlined and it does simplify my task. The only thing I am not sure how to do is "install a signal handler" ?

If anyone could help me to do that, I would be very grateful. And yes, I shall switch to sh afterwards.

My complete code:

Code:
#!/bin/csh

set refIP = 192.168.1.2
set monIP = 192.168.1.3
set coordIP = 192.168.1.1

set trials = ( 1 )
set pingrate = (0.02 0.01)
set pingsize = (504 1016 2040 4088)

set tdate = `date +%d%m%Y_%H%M`
set DSTDIR = /usr/datasets/scp

set scppresent = 1


foreach try ($trials)
  foreach prate ($pingrate)
    foreach psize ($pingsize)
  
      
      (mkdir -p $DSTDIR/${tdate}/${try}/filtered/spp &)
      (ssh root@${monIP} mkdir -p $DSTDIR/${tdate}/${try}/filtered/spp &)

      (tcpdump -i vlan100 -w $DSTDIR/${tdate}/${try}/ref_${tdate}_${psize}_${prate}.pcap &)
      (ssh root@${monIP} tcpdump -i vlan100 -w $DSTDIR/${tdate}/${try}/mon_${tdate}_${psize}_${prate}.pcap &)

      sleep 5

      (scp /usr/FreeBSD-*.iso root@${monIP}:/usr > /home/user/newSCPstats_${tdate}_${psize}_${prate}.txt &)
      
#       while ($scppresent == 1)
# 	if (`ps -ax | grep scp | wc -l | cut -c 8-12` > 1) then
# 	      ping -i ${prate} -s ${psize} $monIP
# 	else
# 	    ssh root@${refIP} killall ping
# 	    set scppresent = 0
# 	endif
#       end

      ping -i ${prate} -s ${psize} -t 255 $monIP

      sleep 15

      (killall tcpdump &)
      (ssh root@${monIP} killall tcpdump &)

      sleep 15

    end
  end
end


echo "Done."
 
Before checking your code, a quick answer for the signal handler story.

Here's a code snippet to demonstrate, how you might let sh(1) handle signals the way you want. BTW, my memory has been wrong as you might NOT want to catch SIGHUP signals, but SIGCHLD signals so you're getting informed if one of your child processes exits.

Code:
sighndl()
{
	echo -n "SIGNAL received"
}

# catch SIGCHLD
trap sighndl chld

# now spawn a process and let it end, so we're getting a SIGCHLD
/bin/echo "."

Every process that spawns and dies after the trap command has been executed, will trigger the signal handler function. I've used such constructs already in the past to get a notification when a child exits and then checking if something needs to be done in the handler function.

Please keep in mind, a SIGCHLD will be fired for every child process that exits (that is, even commands often used for scripting like /bin/echo, /bin/test and the like, so you should check the conditions in your signal handling function).

My original idea to your problem was to scp in the background, start ping in the background, trap SIGCHLD, check if scp was exiting, kill the ping then. That way, you're using the cpu in a very efficient way but you may do it in one of the other 100 possible ways ;)
 
Traps seem unnecessary here, what you need is sh(1)()'s ability to wait for a specific process. For example:

Code:
scp ... &
scppid=$!
ping ... &
pingpid=$!
wait $scppid
kill $pingpid
wait $pingpid

If you combine this with traps, take care that wait terminates prematurely if a trap occurs.
 
Thanks vwe@ and jilles@. The information you have provided is very useful. I shall test them asap.

Cheers,
atwinix
 
Great I got it work! Thanks a lot. The only thing that I now need is to be able to redirect the output of a background process to file. Although I know how to do it, the file being generated is empty and 0B in size!! See the code below:

Code:
scp /usr/testtrans.file root@192.168.1.2:/usr > /root/SCPstats_31052011_504_0.02.txt &


I am running my script as root and checked that it has permissions to write to the directories! Any clues?
 
Are you seeing output on the console? The redirect '>' can be detected and overridden by the calling program. Or it may write to /dev/tty directly.

Observe, the redirect won't work:

Code:
[0]$ (date > /dev/tty) > 1
Thu Jun 16 23:23:00 BST 2011
but this will:
Code:
[0]$ (date > /dev/stdout) > 1
 
Back
Top