您好,登錄后才能下訂單哦!
本篇內容主要講解“c語言怎么實現http下載器”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“c語言怎么實現http下載器”吧!
最近做ota升級需要用到http下載,所以寫了一下http下載器
實現流程
1、解析url網址的域名和文件名
2、獲取ip地址
3、構建http請求頭發送到服務器
4、解析回復
5、下載文件
環境ubuntu linux
c語言
開源鏈接
main.c
#include <stdio.h> #include "http_download.h" int main(int argc, char const *argv[]) { if (argc == 1) { printf("Input a valid URL \n"); exit(0); } else { http_download_file(argv[1]); } return 0; }
http_download.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <netdb.h> #include <fcntl.h> #include "tcp.h" typedef struct { int status_code;//HTTP/1.1 '200' OK char content_type[128];//Content-Type: application/gzip long content_length;//Content-Length: 11683079 char file_name[256]; }resp_header_def; resp_header_def resp;//頭信息 #if 0 下載分為以下幾個過程 1、解析出下載地址中的域名和文件名 2、通過域名獲取服務器的IP地址 3、與目標服務器建立連接 4、構建http請求頭并將其發送到服務器 5、等待服務器響應然后接收響應頭 6、解析響應頭, 判斷返回碼, 分離開響應頭, 并且響應的正文內容以字節形式寫入文件, 正文內容與頭部用兩個\n\r分開 #endif #define print_LOG(format, ...) {\ printf(format, ##__VA_ARGS__);} //解析網址 //輸入url,輸出域名、端口、文件名 static int Parsing_urls(char *url, char *domain, int *port, char *filename) { int i,j,start; char *patterns[] = {"http://", "https://", NULL}; *port = 80; //解析域名,就是http://或者https://到/的內容 for(i = 0; patterns[i]; i++) { if(strncmp(url, patterns[i], strlen(patterns[i])) == 0) { start = strlen(patterns[i]); } } //復制域名 j = 0; for ( i = start; url[i] != '/' && url[i] != '\0'; i++,j++) { domain[j] = url[i]; } domain[i] = '\0'; //解析端口,冒號后面就是端口 char pos = strstr(domain, ":"); if(pos) { sscanf(pos, ":%d", port); } //如果有端口,需要刪掉 for ( i = 0; i < (int)strlen(domain); i++) { if(domain[i] == ':') { domain[i] = '\0'; break; } } //解析下載文件名,/后面就是文件名 j = 0; for ( i = start; url[i] != '\0'; i++) { if(url[i] == '/') { j = i + 1; memcpy(filename, &url[j], strlen(&url[j])); } } i = strlen(&url[j]); filename[i] = '\0'; return 0; } //通過域名獲取ip static int Domain_to_ip(char *domain, char *ip) { int i; struct hostent *host = gethostbyname(domain); if(host == 0) { *ip = NULL; return -1; } //找到不為空的地址 for ( i = 0; host->h_addr_list[i]; i++) { strcpy(ip, inet_ntoa( * (struct in_addr*) host->h_addr_list[i])); break; } return 0; } //構建請求頭信息 static int Set_request_headers(char *header, char *url, char *domain) { int ret = 0; sprintf(header, \ "GET %s HTTP/1.1\r\n"\ "Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\r\n"\ "User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537(KHTML, like Gecko) Chrome/47.0.2526Safari/537.36\r\n"\ "Host:%s\r\n"\ "Connection:close\r\n"\ "\r\n"\ ,url, domain); ret = strlen(header); return ret; } static char *get_response() { int len, lencnt = 0,mem_size = 4096; char *rcvbuff = (char *)malloc( mem_size*sizeof(char) ); char *response = (char *)malloc( mem_size*sizeof(char) ); while((len = tcp_client_rcv(rcvbuff, 1)) != 0) { //動態調整緩存大小 if((lencnt + len) > mem_size)//判斷緩存是否超限 { //重新分配內存 mem_size *= 2; char *tmp = (char *)realloc(response, mem_size*sizeof(char)); if(tmp == NULL) { printf("realloc fail\n"); exit(-1); } response = tmp; } rcvbuff[len] = '\0'; strcat(response, rcvbuff); //找到響應頭的頭部信息, 兩個"\n\r"為分割點 int flag = 0; int i = strlen(response) - 1; for (; response[i] == '\n' || response[i] == '\r'; i--, flag++); { if (flag == 4)//最多找4次,沒找到 break; } lencnt += len; } free(rcvbuff); return response; } //獲取回復頭的信息 static int get_resp_header(const char *response, resp_header_def *resp) { //查找HTTP/ char *pos = strstr(response, "HTTP/"); if (pos) sscanf(pos, "%*s %d", &resp->status_code);//返回狀態碼 pos = strstr(response, "Content-Type:");//返回內容類型 if (pos) sscanf(pos, "%*s %s", resp->content_type); pos = strstr(response, "Content-Length:");//內容的長度(字節) if (pos) sscanf(pos, "%*s %ld", &resp->content_length); return 0; } //打印進度 int progress_bar(int x) { int i; char tmp[100] = {0}; static int x_old = 0; if(x == x_old) { return 0; } x_old = x; i = x/2; if(i > 50) i = 50; memset(tmp, '=', i); printf("\r%d%[%s]", x, tmp); fflush(stdout);//立刻輸出 return 0; } static int download_writefile() { int length = 0; int mem_size = 4096;//mem_size might be enlarge, so reset it int buf_len = mem_size;//read 4k each time int len = 0; int fd = open(resp.file_name, O_CREAT | O_WRONLY, S_IRWXG | S_IRWXO | S_IRWXU); if (fd < 0) { print_LOG("Create file failed\n"); exit(0); } //申請4k緩存 char *buf = (char *)malloc(mem_size * sizeof(char)); //讀取文件 while ((len = tcp_client_rcv(buf, buf_len)) != 0 && length < resp.content_length) { write(fd, buf, len); length += len; progress_bar((length*100/resp.content_length)); } if (length == resp.content_length) { print_LOG("\nDownload successful ^_^\n\n"); } else { print_LOG("Finished length:%d,resp.content_length:%d\n", length, resp.content_length); } close(fd); return 0; } //http下載文件函數 int http_download_file(char *url) { //char url[2048] = "127.0.0.1"; char domain[64] = {0}; char ip_addr[16] = {0}; int port = 80; char file_name[256] = {0}; char header[2048] = {0}; char *response = 0; //解析域名 Parsing_urls(url, domain, &port, file_name); //解析ip Domain_to_ip(domain, ip_addr); print_LOG("download:\n url:%s\n domain:%s\n ip:%s\n port:%d\n filename:%s\n", url, domain, ip_addr, port, file_name); //發送下載請求 Set_request_headers(header, url, domain); if(tcp_client_init(ip_addr, port) == -1) { print_LOG("connect server fail\n"); return -1; } tcp_client_send(header, strlen(header)); print_LOG("\nsend request\n"); //print_LOG("send request:%s\n", header); //解析回復 response = get_response(); get_resp_header(response, &resp); print_LOG("response:%s\n", response); free(response); strcpy(resp.file_name, file_name); print_LOG("\nres:\n content_length:%d\n file_name:%s\n Content-Type:%s\n", resp.content_length, resp.file_name, resp.content_type); //下載文件 print_LOG("\ndownload %s start ...\n", resp.file_name); download_writefile(); return 0; }
download.h
#ifndef __HTTP_DOWNLOAD_H #define __HTTP_DOWNLOAD_H int http_download_file(char *url); #endif
tcp.c
//-------tcp相關頭文件------ #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> //close() static int socket_fd = 0; //tcp_client_init() //1、創建socket //2、配置為客戶端 //3、配置要連接的服務器ip和端口以及協議類型 //4、連接服務器 //5、收發數據 //6、關閉連接 int tcp_client_init(char *ip, int port) { int ret; //1 2 socket_fd = socket(AF_INET, SOCK_STREAM, 0); if(socket_fd == -1) { printf("create socket fail\n"); return -1; } //3 struct sockaddr_in servaddr; servaddr.sin_family = AF_INET;//IPv4協議 servaddr.sin_port = htons(port);//服務器端口號 servaddr.sin_addr.s_addr = inet_addr(ip);//設置服務器 //4 ret = connect(socket_fd, &servaddr, sizeof(servaddr)); if(ret == -1) { printf("connect %s fail\n", ip); return -1; } } //tcp_client_send() int tcp_client_send(char *buff, int len) { int ret = 0; ret = write(socket_fd, buff, len); return ret; } //tcp_client_rcv() int tcp_client_rcv(char *buff, int len) { int ret; ret = read(socket_fd, buff, len); return ret; } //tcp_client_close() int tcp_client_close() { close(socket_fd); } #define CLENT_NUM 2 struct sockaddr_in sSever_c_sd[CLENT_NUM]; static int socket_s_fd = 0; static int socket_c_fd[CLENT_NUM] = {0}; //tcp_server_init() #if 0 1、創建socket 2、設置本地ip和端口以及協議類型 3、綁定 4、監聽 5、等待客戶端連接 6、收發數據 7、關閉連接 #endif int tcp_server_init(int port) { int ret; //1 socket_s_fd = socket(AF_INET, SOCK_STREAM, 0); if(socket_s_fd == -1) { printf("create socket fail\n"); return -1; } else { printf("create socket ok\n"); } //2 struct sockaddr_in local_addr,c_addr; local_addr.sin_family = AF_INET;//IPv4協議 local_addr.sin_port = htons(port);//服務器端口號 local_addr.sin_addr.s_addr = INADDR_ANY;//設置服務器ip //3 ret = bind(socket_s_fd, &local_addr, sizeof(local_addr)); if(ret == -1) { printf("bind fail\n"); close(socket_s_fd); return -1; } else { printf("bind ok\n"); } //4 ret = listen(socket_s_fd, 3); if(ret == -1) { printf("listen fail\n"); close(socket_s_fd); return -1; } else { printf("listen ok\n"); } //5 socklen_t addrlen = 0; while(1) { printf("wait client conect\n"); socket_c_fd[0] = accept(socket_s_fd, &c_addr, &addrlen); if(addrlen != 0) break; sleep(1); } printf("client conect\n"); return 0; } //tcp_server_send() int tcp_server_send(char c, char *buff, int len) { write(socket_c_fd[c], buff, len); } //tcp_server_rcv() int tcp_server_rcv(char c, char *buff, int len) { int ret; ret = read(socket_c_fd[c], buff, len); return ret; } //tcp_server_close() int tcp_server_close() { close(socket_s_fd); }
tcp.h
#ifndef __TCP_H #define __TCP_H int tcp_client_init(char *ip, int port); int tcp_client_send(unsigned char *buff, int len); int tcp_client_rcv(unsigned char *buff, int len); int tcp_client_close(); int tcp_server_init( int port); int tcp_server_send(char c, unsigned char *buff, int len); int tcp_server_rcv(char c, unsigned char *buff, int len); int tcp_server_close(); #endif
編譯腳本
rm -rf main sscom32.zip gcc main.c http_download.c tcp.c -o main -w ./main http://xzd.197946.com/sscom32.zip
測試效果
http://xzd.197946.com/sscom32.zip
到此,相信大家對“c語言怎么實現http下載器”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。