linux网络编程之断点传输文件

来源:互联网 发布:王者荣耀kda最新算法 编辑:程序博客网 时间:2024/06/05 13:23
以下载链接“http://www.boa.org/boa-0.94.13.tar.gz”为例:断点续传实验大概步骤:=====================1,使用gethostbyname()获取站点“www.boa.org”的IP地址2,以“boa-0.94.13.tar.gz”为例,构建HTTP请求报文首部:   char *httpreq = "GET /boa-0.94.13.tar.gz HTTP/1.1\r\n"                   "Range: bytes=%d-%d\r\n"                   "Host: %s\r\n\r\n"                    begin, end, host);注意:    A) 以上字符串httpreq就是发送给远程主机www.boa.org的HTTP请求报文,通过TCP发送    B) Range字段是要求主机发送申请文件的部分内容,begin和end分别是文件的开始和结束       B.1 如果写成 "Range: bytes=0-\r\n",代表要求主机发送全文       B.2 如果写成 "Range: bytes=-1000\r\n",代表要求主机发送前1000个字节       B.3 如果写成 "Range: bytes=0-200\r\n",代表要求主机发送前200个字节    C) 正常情况下,HTTP服务器会对这个请求报文返回206,并给出实际返回的字节数和范围:       C.1 "Content-Length: 1000" 这个字段代表本次HTTP发来的数据大小为1000个字节(不含HTTP首部)       C.2 "Content-Range: bytes 2000-2999/9999" 代表本次传送的数据范围是第2000-2999个字节(共1000个字节),而所请求的文件总大小是9999个字节。3,将收到的报文的HTTP首部去掉(HTTP首部是指从开头到\r\n\r\n结尾的部分),剩下的就是下载的文件内容4,将文件内容以非缓冲方式保存下来。5,如果发生下载时网络断线,或者人为终止了下载进程,那么在下一次下载时先获取当前已下载部分的大小,并作为Range参数告知远端HTTP服务器,要求发送部分文件,实现断点续传,节约网络流量节约时间。
#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <sys/stat.h>#include <netdb.h>#include <arpa/inet.h>#include <netinet/in.h>#include <sys/socket.h>#include <string.h>#include <strings.h>#include <sys/types.h>#include <fcntl.h>#include <assert.h>#include <stdbool.h>#include "common.h"#define RWRWRW  (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)#define SERV_PORT   80#define FILENAME    "boa-0.94.13.tar.gz"typedef struct sockaddr SA;void http_request(char *buf, int size, const char *filename                            , const int begin, const char *host);int main(void){    int sockfd;    struct sockaddr_in servaddr;    struct hostent *hptr = NULL;    struct in_addr **pptr = NULL;    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {        err_quit("socket error");    }    char *hostname = "www.boa.org";    if ((hptr = gethostbyname(hostname)) == NULL) {        err_quit("gethostbyname error for host: %s: %s",                    hostname, hstrerror(h_errno));    }    pptr = (struct in_addr**)hptr->h_addr_list;    bzero(&servaddr, sizeof(servaddr));    servaddr.sin_family = AF_INET;    servaddr.sin_port   = htons(SERV_PORT);    memcpy(&servaddr.sin_addr, *pptr, sizeof(struct in_addr));    if (connect(sockfd, (SA *)&servaddr, sizeof(servaddr)) < 0) {        err_quit("connect error");    }    int fd;    int file_size;    struct stat statbuf;    if (access(FILENAME, F_OK)) {        if ((fd = open(FILENAME, O_WRONLY|O_CREAT, RWRWRW)) < 0) {            err_sys("create %s failure", FILENAME);        }        file_size = 0;    } else {        if ((fd = open(FILENAME, O_APPEND|O_WRONLY, RWRWRW)) < 0) {            err_sys("open %s failure", FILENAME);        }        if (stat(FILENAME, &statbuf) < 0) {            err_sys("stat error");        }        file_size = statbuf.st_size;    }#ifdef  DEBUG    printf("      host:\t%s\n", hostname);    printf("  filename:\t%s\n", FILENAME);    printf("start size:\t%d\n", file_size);    printf("------------------------------------------------\n\n");#endif    char request[MAXLINE];    http_request(request, sizeof(request), FILENAME, file_size, hostname);    if (write(sockfd, request, strlen(request)) != strlen(request)) {        err_quit("request failure");    }    char recvbuf[4096];    int nread;    bool flage = true;    char tar[] = "\r\n\r\n";    char *begin = NULL;    while (1) {        bzero(recvbuf, sizeof(recvbuf));        if ((nread = read(sockfd, recvbuf, sizeof(recvbuf))) <= 0) {            if (0 == nread) {                break;            } else {                err_sys("read error");            }        }        if (flage) {            if ((begin = strstr(recvbuf, tar)) == NULL) {                continue;            } else {                write(fd, begin+strlen(tar), nread-(begin-recvbuf)-strlen(tar));                flage = false;            }        }        if (!flage) {            if (write(fd, recvbuf, nread) != nread) {                err_quit("write error");            }        }#ifdef  DEBUG        printf("******");        fflush(stdout);#endif    }/*    if (stat(FILENAME, &statbuf) < 0) {        err_quit("stat failure");    } else {        if (statbuf.st_size == full_size) {            printf("---success!---\n");        }    }*/    printf("---success!---\n");    return EXIT_SUCCESS;}void http_request(char *buf, int size, const char *filename, const int begin, const char *host){    assert(buf);    assert(filename);    assert(host);    bzero(buf, size);    snprintf(buf, size, "GET /%s "                        "HTTP/1.1\r\n"                        "Range: bytes=%d-\r\n"                        "Host: %s\r\n\r\n", filename, begin, host);}
原创粉丝点击