今天剛學了一點shell指令碼的編程知識,寫了一個ftp指令碼,如果沒有設定目錄則設定目錄,並上傳檔案到伺服器該二級目錄。如下:
#!/bin/shcp $1 $2ftp -n $3 <<EOFquote USER $4quote PASS $5mkdir $6cd $6mkdir $7cd $7binaryput $2 $1quitEOF
其中$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的執行。這個不是關閉子進程就行的,目前也沒找到好的方法。