本文由 @lonelyrains 出品,转载请注明出处。
文章链接: http://blog.csdn.net/lonelyrains/article/details/6636113
今天刚学了一点shell脚本的编程知识,写了一个ftp脚本,如果没有设置目录则设置目录,并上传文件到服务器该二级目录。如下:
#!/bin/sh
cp $1 $2
ftp -n $3 <<EOF
quote USER $4
quote PASS $5
mkdir $6
cd $6
mkdir $7
cd $7
binary
put $2 $1
quit
EOF
其中$1、$2、$3、$4、$5、$6、$7均为输入参数,分别表示正在使用的文件、需要上传的备份文件、远程主机ip地址、ftp服务器用户名、ftp服务器密码、ftp服务器一级目录、ftp服务器二级目录。
调用该脚本的C程序代码为:
pid_t pid;
if((pid = fork()) < 0)
perror("fork error");
else if(pid == 0)
{
if(execl("/root/Projects/ftp_test/upload",
"upload","a.txt","bk_a.txt","192.168.16.150",
"root","root","record","0001",NULL) < 0)
perror("execl error");
}
waitpid(pid,NULL,0);//以阻塞方式调用子进程,直到ftp的返回结果
问题是这样一来,程序不能知道ftp到底执行成功没有,如果没有,waitpid(pid,NULL,0)需要等大约3分钟才能知道结果。网上查了很多ftp的资料,都没有客户端设置超时时间的方法。后来想到用程序计时的方式和非阻塞等待的方式调用waitpid,修改的代码如下:
pid_t pid,pidrtn;
struct timeval tvstart,tvend;
float timeuse=0;
gettimeofday(&tvstart,NULL);
if((pid = fork()) < 0)
perror("fork error");
else if(pid == 0)
{
if(execl("/root/Projects/ftp_test/upload",
"upload","a.txt","bk_a.txt","192.168.16.150",
"root","root","record","0001",NULL) < 0)
perror("execl error");
}
//调用ftp的脚本,自设定时,waitpid的WNOHANG选项,参考waitpid.c
while(timeuse < 10)
{
pidrtn = waitpid(pid,NULL,WNOHANG);
if(pidrtn == 0)
{
//printf("the child process has not exited\n");
sleep(1);
}
else break;
gettimeofday(&tvend,NULL);
timeuse = 1000000*(tvend.tv_sec-tvstart.tv_sec)
+tvend.tv_usec-tvstart.tv_usec;
timeuse /=1000000;
}
if(pidrtn == 0)
{
char cmd[200];
//杀死子进程,fork在父进程中返回的是子进程pid
sprintf(cmd,"kill %d",pid);
system(cmd);//仍然关不掉已在进行的ftp连接尝试
printf("ftp-connect timeout\n");
}
else printf("pidrtn:%d",pidrtn);
这样一来就保证了ftp超时也能让程序知道,超时时间也可以自己设置,而且可以执行后续的程序而不用挂死在这里等ftp超时。
但是仍然有不完善的地方。大多数情况下,上传需要多少时间程序员大概知道,从而设置较合理的超时时间。但是仍存在可能突然文件很大,而超过超时时间,在超时时间之后实际上传成功,而程序内显示超时。所以,可以根据需上传的文件大小动态设置超时时间。当然,最理想的是,超过设定的超时时间之后,马上关掉ftp的执行。这个不是关闭子进程就行的,目前也没找到好的方法。