最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

c語言實現http下載器的方法

 更新時間:2021年07月30日 10:33:29   作者:鍋鍋是鍋鍋  
這篇文章主要介紹了c語言實現http下載器的相關知識,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下

一、介紹

最近做ota升級需要用到http下載,所以寫了一下http下載器
實現流程
1、解析url網址的域名和文件名
2、獲取ip地址
3、構建http請求頭發(fā)送到服務器
4、解析回復
5、下載文件

環(huán)境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請求頭并將其發(fā)送到服務器
5、等待服務器響應然后接收響應頭
6、解析響應頭, 判斷返回碼, 分離開響應頭, 并且響應的正文內容以字節(jié)形式寫入文件, 正文內容與頭部用兩個\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)
    {
        //動態(tài)調整緩存大小
        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);//返回狀態(tài)碼

    pos = strstr(response, "Content-Type:");//返回內容類型
    if (pos)
        sscanf(pos, "%*s %s", resp->content_type);

    pos = strstr(response, "Content-Length:");//內容的長度(字節(jié))
    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);

    //發(fā)送下載請求
    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、創(chuàng)建socket
//2、配置為客戶端
//3、配置要連接的服務器ip和端口以及協(xié)議類型
//4、連接服務器
//5、收發(fā)數據
//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協(xié)議	
	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、創(chuàng)建socket
2、設置本地ip和端口以及協(xié)議類型
3、綁定
4、監(jiān)聽
5、等待客戶端連接
6、收發(fā)數據
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協(xié)議	
	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下載器的文章就介紹到這了,更多相關c語言http下載器內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:

相關文章

  • Qt數據庫應用之實現通用數據庫請求

    Qt數據庫應用之實現通用數據庫請求

    這篇文章主要為大家介紹了Qt中是如何實現通用數據庫請求的,文中的示例代碼講解詳細,對我們學習Qt有一定幫助,感興趣的小伙伴可以了解一下
    2022-03-03
  • C++實現迷宮生成與解決

    C++實現迷宮生成與解決

    這篇文章主要為大家詳細介紹了C++實現迷宮生成與解決,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-12-12
  • 基于MFC實現類的序列化詳解

    基于MFC實現類的序列化詳解

    序列化是將程序中的對象以一種二進制格式存儲到存儲設備中(例如文本/數據庫等),以實現“永生”或隨意“流動”。本文將為大家詳細講講如何基于MFC實現類的序列化,需要的可以參考一下
    2022-07-07
  • OpenCV去除綠幕摳圖源碼

    OpenCV去除綠幕摳圖源碼

    這篇文章主要介紹了OpenCV去除綠幕摳圖,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-05-05
  • 詳解C++編程中類的聲明和對象成員的引用

    詳解C++編程中類的聲明和對象成員的引用

    這篇文章主要介紹了詳解C++編程中類的聲明和對象成員的引用,是C++入門學習中的基礎知識,需要的朋友可以參考下
    2015-09-09
  • C++ CTreeview的checkbox使用方法

    C++ CTreeview的checkbox使用方法

    這篇文章主要介紹了C++ CTreeview的checkbox使用方法的相關資料,需要的朋友可以參考下
    2015-06-06
  • C++之普通成員函數、虛函數以及純虛函數的區(qū)別與用法要點

    C++之普通成員函數、虛函數以及純虛函數的區(qū)別與用法要點

    本篇文章主要介紹了C++中的普通成員函數、虛函數以及純虛函數,非常的詳細,有需要的朋友可以參考下
    2015-07-07
  • C++定義和初始化string對象實例詳解

    C++定義和初始化string對象實例詳解

    這篇文章主要為大家介紹了C++定義和初始化string對象實例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-12-12
  • 通過實例詳解C語言函數返回值

    通過實例詳解C語言函數返回值

    函數的返回值是指函數被調用之后,執(zhí)行函數體中的程序段所取得的并返回給主調函數的值,下面這篇文章主要給大家介紹了關于C語言函數返回值的相關資料,需要的朋友可以參考下
    2022-01-01
  • 基于Qt編寫全能播放組件的示例代碼

    基于Qt編寫全能播放組件的示例代碼

    這篇文章主要為大家詳細介紹了如何基于Qt編寫全能播放組件,可以支持ffmpeg2/3/4/5/6/Qt4/5/6,感興趣的小伙伴可以跟隨小編一起學習一下
    2023-06-06

最新評論

阜新市| 饶河县| 温宿县| 舞钢市| 无棣县| 巩义市| 仲巴县| 彰化县| 日土县| 晴隆县| 磴口县| 任丘市| 游戏| 尉犁县| 和静县| 开鲁县| 建阳市| 中方县| 雷州市| 福安市| 沙坪坝区| 蓬莱市| 禄丰县| 无为县| 新干县| 临武县| 景谷| 天全县| 巧家县| 梁平县| 馆陶县| 临武县| 繁峙县| 象山县| 龙州县| 无极县| 名山县| 讷河市| 芜湖县| 清苑县| 修文县|