1、文件下載指令應用
支持斷點續傳
linux wget命令。curl -C - -O "https://curl.haxx.se/download/archeology/curl-7.58.0.tar.gz"
curl -C - -O "https://curl.haxx.se/download/archeology/md5.txt"
直接覆蓋
curl "https://curl.haxx.se/download/archeology/curl-7.58.0.tar.gz" -o curl-7.58.0.tar.gz --progress
curl "https://curl.haxx.se/download/archeology/md5.txt" -o md5.txt --progress
系統自帶的wget指令下載文件也類似
wget "https://curl.haxx.se/download/archeology/curl-7.58.0.tar.gz"
wget -O curl-7.58.0.tar.gz "https://curl.haxx.se/download/archeology/curl-7.58.0.tar.gz"
L大的openwrt固件下載,?
2、產品固件更新應用demo
upgrade.sh
#!/bin/sh url="https://curl.haxx.se/download/archeology/" while true do#1)download filemd5_url=${url}"md5.txt"#curl md5_url -o md5.txt --progresswget -O md5.txt "$md5_url"version=$(sed -n 1p md5.txt)filename=$(sed -n 2p md5.txt)md5=$(sed -n 3p md5.txt)version_bak=$(sed -n 1p md5_bak.txt)echo $version echo $filenameecho $md5 echo $version_bak#2)md5sum firmware if [[ "$version" != "$version_bak" ]];then cp md5.txt md5_bak.txt download_url=${url}${filename} download_url=${download_url%$'\r'}#curl "$download_url" -o $filename --progresswget -O $filename "$download_url" md5_calc=$(md5sum $filename|cut -d ' ' -f1)#3)replace app file---> rebootif [ "$md5"=="$md5_calc" ] ; then ./kill_app.sh#replace upgrade file./run_app.shrm $filenametime=$(date "+%Y-%m-%d %H:%M:%S")echo "${time} upgrade $md5_calc $filename " >> log.txtelse echo "upgrade file md5sum err !"fielse echo "local version is the latest version !"fisleep 10 done
wr802n刷openwrt固件、?
3、 md5.txt
?md5.txt文件內置3行關鍵信息
高通9531刷openwrt、7.58.0
curl-7.58.0.tar.gz
7e9e9d5405c61148d53035426f162b0a
?
4、curl安裝
openwrt最新固件?https://curl.haxx.se/
./configure --prefix=/usr/local/curl
make
sudo make install
export PATH=$PATH:/usr/local/curl/bin
export LD_LIBRARY_PATH=/usr/local/curl/lib:$LD_LIBRARY_PATH
?
5、curl移植
./configure --prefix=/home/dong/curl/curl-7.58.0/_install --host=arm-linux-gnueabihf CC=arm-linux-gnueabihf-gcc CXX=arm-linux-gnueabihf-g++
make
sudo make install
?
6、 wget編譯,安裝
https://ftp.gnu.org/gnu/wget/
#?tar?zxvf?wget-1.9.1.tar.gz?
#?cd?wget-1.9.1?
#?./configure?
#?make?
#?make?install
?
7、progress
wget -c https://ftp.gnu.org/gnu/wget/wget-1.19.tar.gz -o load.log
progress.sh
#wget -c https://ftp.gnu.org/gnu/wget/wget-1.19.tar.gz -o load.logwhile true dosed -n '/..........\>/p' load.log | sed '$d' | sed -n '$p' | awk '{print $1,$2,$3,$4,$5,$6,$7}' sed -n '/...\>/p' load.log | sed '$d' | sed -n '$p' | awk '{print $1,$2,$3,$4}'sleep 1done
?
8、progress.c
#include <stdio.h> #include <stdlib.h> #include <unistd.h> //類似wget的進度條的實現,實際就是轉移符\r的使用,\r的作用是返回至行首而不換行 int main(int argc, char *argv[]) {unsigned len = 60;char *bar = (char *)malloc(sizeof(char) * (len + 1));for (int i = 0; i < len + 1; ++i){bar[i] = '#';}for (int i = 0; i < len; ++i){printf("progress:[%s]%d%%\r", bar+len-i, i+1);fflush(stdout);//一定要fflush,否則不會會因為緩沖無法定時輸出。usleep(100000);//sleep(1); }printf("\n");return 0; }
?
9、checkurl.sh
#!/bin/bash usage(){echo "Usage:$0 url"exit 1 }checkurl(){local num=`curl -I -m 5 -s -w "%{http_code}\n" -o /dev/null $1 |egrep "(200|301|302)"|wc -l`if [ $num -eq 1 ] thenecho "ok"elseecho "$1"fi }main(){if [ $# -ne 1 ]thenusageficheckurl $1}main $*
sh checkurl.sh www.vbill.cn
?
10、c語言文件下載,帶進度條
https://blog.csdn.net/qq_31629063/article/details/80846673
https://www.cnblogs.com/wainiwann/p/3148884.html
?
url2file.c ,已經忘了在哪兒淘的。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <sys/types.h> #include <sys/socket.h> #include <fcntl.h> #include <unistd.h> #include <netdb.h> #include <errno.h>#define HOST_NAME_LEN 256 #define URI_MAX_LEN 2048 #define RECV_BUF 8192 #define RCV_SND_TIMEOUT (10*1000) //收發數據超時時間(ms)typedef struct {int sock; //與服務器通信的socketFILE *in; //sock描述符轉為文件指針,方便讀寫char host_name[HOST_NAME_LEN]; //主機名int port; //主機端口號char uri[URI_MAX_LEN]; //資源路徑char buffer[RECV_BUF]; //讀寫緩沖int status_code; //http狀態碼int chunked_flag; //chunked傳輸的標志位int len; //Content-length里的長度char location[URI_MAX_LEN]; //重定向地址char *save_path; //保存內容的路徑指針FILE *save_file; //保存內容的文件指針int recv_data_len; //收到數據的總長度time_t start_recv_time; //開始接受數據的時間time_t end_recv_time; //結束接受數據的時間 } http_t;/* 打印宏 */ #define MSG_DEBUG 0x01 #define MSG_INFO 0x02 #define MSG_ERROR 0x04static int print_level = /*MSG_DEBUG |*/ MSG_INFO | MSG_ERROR;#define lprintf(level, format, argv...) do{ \if(level & print_level) \printf("[%s][%s(%d)]:"format, #level, __FUNCTION__, __LINE__, ##argv); \ }while(0)#define MIN(x, y) ((x) > (y) ? (y) : (x))#define HTTP_OK 200 #define HTTP_REDIRECT 302 #define HTTP_NOT_FOUND 404/* 不區分大小寫的strstr */ char *strncasestr(char *str, char *sub) {if(!str || !sub)return NULL;int len = strlen(sub);if (len == 0){return NULL;}while (*str){if (strncasecmp(str, sub, len) == 0){return str;}++str;}return NULL; }/* 解析URL, 成功返回0,失敗返回-1 */ /* http://127.0.0.1:8080/testfile */ int parser_URL(char *url, http_t *info) {char *tmp = url, *start = NULL, *end = NULL;int len = 0;/* 跳過http:// */if(strncasestr(tmp, "http://")){ tmp += strlen("http://");}start = tmp;if(!(tmp = strchr(start, '/'))){lprintf(MSG_ERROR, "url invaild\n");return -1; }end = tmp;/*解析端口號和主機*/info->port = 80; //先附默認值80 len = MIN(end - start, HOST_NAME_LEN - 1);strncpy(info->host_name, start, len);info->host_name[len] = '\0';if((tmp = strchr(start, ':')) && tmp < end){info->port = atoi(tmp + 1);if(info->port <= 0 || info->port >= 65535){lprintf(MSG_ERROR, "url port invaild\n");return -1;}/* 覆蓋之前的賦值 */len = MIN(tmp - start, HOST_NAME_LEN - 1);strncpy(info->host_name, start, len);info->host_name[len] = '\0';}/* 復制uri */start = end;strncpy(info->uri, start, URI_MAX_LEN - 1);lprintf(MSG_INFO, "parse url ok\nhost:%s, port:%d, uri:%s\n", info->host_name, info->port, info->uri);return 0; }/* dns解析,返回解析到的第一個地址,失敗返回-1,成功則返回相應地址 */ unsigned long dns(char* host_name) {struct hostent* host;struct in_addr addr;char **pp;host = gethostbyname(host_name);if (host == NULL){lprintf(MSG_ERROR, "gethostbyname %s failed\n", host_name);return -1;}pp = host->h_addr_list;if (*pp!=NULL){addr.s_addr = *((unsigned int *)*pp);lprintf(MSG_INFO, "%s address is %s\n", host_name, inet_ntoa(addr));pp++;return addr.s_addr;}return -1; }/* 設置發送接收超時 */ int set_socket_option(int sock) {struct timeval timeout;timeout.tv_sec = RCV_SND_TIMEOUT/1000;timeout.tv_usec = RCV_SND_TIMEOUT%1000*1000;lprintf(MSG_DEBUG, "%ds %dus\n", (int)timeout.tv_sec, (int)timeout.tv_usec);//設置socket為非阻塞// fcntl(sock ,F_SETFL, O_NONBLOCK); //以非阻塞的方式,connect需要重新處理// 設置發送超時if(-1 == setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(struct timeval))){lprintf(MSG_ERROR, "setsockopt error: %m\n");return -1;}// 設置接送超時if(-1 == setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(struct timeval))){lprintf(MSG_ERROR, "setsockopt error: %m\n");return -1;}return 0; }/* 連接到服務器 */ int connect_server(http_t *info) {int sockfd;struct sockaddr_in server;unsigned long addr = 0;unsigned short port = info->port;sockfd = socket(AF_INET, SOCK_STREAM, 0);if (-1 == sockfd){lprintf(MSG_ERROR, "socket create failed\n");goto failed;}if(-1 == set_socket_option(sockfd)){goto failed;}if ((addr = dns(info->host_name)) == -1){lprintf(MSG_ERROR, "Get Dns Failed\n");goto failed;}memset(&server, 0, sizeof(server));server.sin_family = AF_INET; server.sin_port = htons(port); server.sin_addr.s_addr = addr;if (-1 == connect(sockfd, (struct sockaddr *)&server, sizeof(struct sockaddr))){lprintf(MSG_ERROR, "connect failed: %m\n");goto failed;}info->sock = sockfd;return 0;failed:if(sockfd != -1)close(sockfd);return -1; }/* 發送http請求 */ int send_request(http_t *info) {int len;memset(info->buffer, 0x0, RECV_BUF);snprintf(info->buffer, RECV_BUF - 1, "GET %s HTTP/1.1\r\n""Accept: */*\r\n""User-Agent: Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)\r\n""Host: %s\r\n""Connection: Close\r\n\r\n", info->uri, info->host_name);lprintf(MSG_DEBUG, "request:\n%s\n", info->buffer);return send(info->sock, info->buffer, strlen(info->buffer), 0); }/* 解析http頭 */ int parse_http_header(http_t *info) {char *p = NULL;// 解析第一行fgets(info->buffer, RECV_BUF, info->in);p = strchr(info->buffer, ' ');//簡單檢查http頭第一行是否合法if(!p || !strcasestr(info->buffer, "HTTP")){lprintf(MSG_ERROR, "bad http head\n");return -1;}info->status_code = atoi(p + 1); lprintf(MSG_DEBUG, "http status code: %d\n", info->status_code);// 循環讀取解析http頭while(fgets(info->buffer, RECV_BUF, info->in)){// 判斷頭部是否讀完if(!strcmp(info->buffer, "\r\n")){return 0; /* 頭解析正常 */}lprintf(MSG_DEBUG, "%s", info->buffer);// 解析長度 Content-length: 554if(p = strncasestr(info->buffer, "Content-length")){p = strchr(p, ':');p += 2; // 跳過冒號和后面的空格info->len = atoi(p);lprintf(MSG_INFO, "Content-length: %d\n", info->len);}else if(p = strncasestr(info->buffer, "Transfer-Encoding")){if(strncasestr(info->buffer, "chunked")){info->chunked_flag = 1;}else{/* 不支持其他編碼的傳送方式 */lprintf(MSG_ERROR, "Not support %s", info->buffer);return -1;}lprintf(MSG_INFO, "%s", info->buffer);}else if(p = strncasestr(info->buffer, "Location")){p = strchr(p, ':');p += 2; // 跳過冒號和后面的空格strncpy(info->location, p, URI_MAX_LEN - 1);lprintf(MSG_INFO, "Location: %s\n", info->location);}}lprintf(MSG_ERROR, "bad http head\n");return -1; /* 頭解析出錯 */ }/* 保存服務器響應的內容 */ int save_data(http_t *info, const char *buf, int len) {int total_len = len;int write_len = 0;// 文件沒有打開則先打開if(!info->save_file){info->save_file = fopen(info->save_path, "w");if(!info->save_file){lprintf(MSG_ERROR, "fopen %s error: %m\n", info->save_path);return -1;}}while(total_len){write_len = fwrite(buf, sizeof(char), len, info->save_file);if(write_len < len && errno != EINTR){lprintf(MSG_ERROR, "fwrite error: %m\n");return -1;}total_len -= write_len;} }/* 讀數據 */ int read_data(http_t *info, int len) {int total_len = len;int read_len = 0;int rtn_len = 0;while(total_len){read_len = MIN(total_len, RECV_BUF);// lprintf(MSG_DEBUG, "need read len: %d\n", read_len);rtn_len = fread(info->buffer, sizeof(char), read_len, info->in);if(rtn_len < read_len){if(ferror(info->in)){if(errno == EINTR) /* 信號中斷了讀操作 */{; /* 不做處理繼續往下走 */}else if(errno == EAGAIN || errno == EWOULDBLOCK) /* 超時 */{lprintf(MSG_ERROR, "socket recvice timeout: %dms\n", RCV_SND_TIMEOUT);total_len -= rtn_len;lprintf(MSG_DEBUG, "read len: %d\n", rtn_len);break;}else /* 其他錯誤 */{lprintf(MSG_ERROR, "fread error: %m\n");break;}}else /* 讀到文件尾 */{lprintf(MSG_ERROR, "socket closed by peer\n");total_len -= rtn_len;lprintf(MSG_DEBUG, "read len: %d\n", rtn_len);break;}}// lprintf(MSG_DEBUG, " %s\n", info->buffer);total_len -= rtn_len;lprintf(MSG_DEBUG, "read len: %d\n", rtn_len);if(-1 == save_data(info, info->buffer, rtn_len)){return -1;}info->recv_data_len += rtn_len;}if(total_len != 0){lprintf(MSG_ERROR, "we need to read %d bytes, but read %d bytes now\n", len, len - total_len);return -1;} }/* 接收服務器發回的chunked數據 */ int recv_chunked_response(http_t *info) {long part_len;//有chunked,content length就沒有了do{// 獲取這一個部分的長度fgets(info->buffer, RECV_BUF, info->in);part_len = strtol(info->buffer, NULL, 16);lprintf(MSG_DEBUG, "part len: %ld\n", part_len);if(-1 == read_data(info, part_len))return -1;//讀走后面的\r\n兩個字符if(2 != fread(info->buffer, sizeof(char), 2, info->in)){lprintf(MSG_ERROR, "fread \\r\\n error : %m\n");return -1;}}while(part_len);return 0; }/* 計算平均下載速度,單位byte/s */ float calc_download_speed(http_t *info) {int diff_time = 0; float speed = 0.0;diff_time = info->end_recv_time - info->start_recv_time;/* 最小間隔1s,避免計算浮點數結果為inf */if(0 == diff_time)diff_time = 1;speed = (float)info->recv_data_len / diff_time;return speed; }/* 接收服務器的響應數據 */ int recv_response(http_t *info) {int len = 0, total_len = info->len;if(info->chunked_flag)return recv_chunked_response(info);if(-1 == read_data(info, total_len))return -1;return 0; }/* 清理操作 */ void clean_up(http_t *info) {if(info->in)fclose(info->in);if(-1 != info->sock)close(info->sock);if(info->save_file)fclose(info->save_file);if(info)free(info); }/* 下載主函數 */ int http_download(char *url, char *save_path) {http_t *info = NULL;char tmp[URI_MAX_LEN] = {0};if(!url || !save_path)return -1;//初始化結構體info = malloc(sizeof(http_t));if(!info){lprintf(MSG_ERROR, "malloc failed\n");return -1;}memset(info, 0x0, sizeof(http_t));info->sock = -1;info->save_path = save_path;// 解析urlif(-1 == parser_URL(url, info))goto failed;// 連接到serverif(-1 == connect_server(info))goto failed;// 發送http請求報文if(-1 == send_request(info))goto failed;// 接收響應的頭信息info->in = fdopen(info->sock, "r");if(!info->in){lprintf(MSG_ERROR, "fdopen error\n");goto failed;}// 解析頭部if(-1 == parse_http_header(info))goto failed;switch(info->status_code){case HTTP_OK:// 接收數據lprintf(MSG_DEBUG, "recv data now\n");info->start_recv_time = time(0);if(-1 == recv_response(info))goto failed;info->end_recv_time = time(0);lprintf(MSG_INFO, "recv %d bytes\n", info->recv_data_len);lprintf(MSG_INFO, "Average download speed: %.2fKB/s\n", calc_download_speed(info)/1000);break;case HTTP_REDIRECT:// 重啟本函數lprintf(MSG_INFO, "redirect: %s\n", info->location);strncpy(tmp, info->location, URI_MAX_LEN - 1);clean_up(info);return http_download(tmp, save_path);case HTTP_NOT_FOUND:// 退出lprintf(MSG_ERROR, "Page not found\n");goto failed;break;default:lprintf(MSG_INFO, "Not supported http code %d\n", info->status_code);goto failed;}clean_up(info);return 0; failed:clean_up(info);return -1; }/**************************************************************************** 測試用例: (1)chunked接收測試 ./a.out "http://www.httpwatch.com/httpgallery/chunked/chunkedimage.aspx" test.aspx (2)重定向測試 ./a.out "192.168.10.1/main.html" test.txt (3)錯誤輸入測試 ./a.out "32131233" test.txt (4)根目錄輸入測試 ./a.out "www.baidu.com/" test.txt (5)端口號訪問測試 ./a.out "192.168.0.200:8000/FS_AC6V1.0BR_V15.03.4.12_multi_TD01.bin" test.txt ****************************************************************************/int main(int argc, char *argv[]) {if(argc < 3)return -1;http_download(argv[1], argv[2]);return 0; }
?