荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: jjk (UNIX+C+XML+?? 傻了?), 信区: Linux
标  题: 一个简明的断点续传程序                 guru (转寄)[转载]
发信站: 荔园晨风BBS站 (Thu Apr 25 10:25:48 2002), 转信

【 以下文字转载自 jjk 的信箱 】
【 原文由 jjk.bbs@apue.dhs.org 所发表 】
发信人: Suning (资优生+干苦力), 信区: LINUX
标  题: 一个简明的断点续传程序
发信站: 武汉白云黄鹤站 (Sat Sep 16 10:59:28 2000), 转信

                        一个简明的断点续传程序.

发信站: BBS 水木清华站 (Wed Apr 26 00:14:44 2000)
/*      Get and Resume Elite EDition source code Ver .4 (Uh huh!)
        First off, sorry about the mess and lack of error checking..
                I'll clean it up later ;)
Get and Resume Elite EDition (GREED)
Copyright (C) 1999  Anoakie Turner
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
For more information on the GPL, please go to:
http://www.gnu.org/copyleft/gpl.html
        Contact:  Anoakie Turner
                  Anoakie.Turner@asu.edu
                  13240 N. 94th Pl.
                  Scottsdale, AZ 85260
*/
/*
**  To compile, use g++ -O -Wall -o greed greed.cpp
*/
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#define HTTP 1
#define FTP 2
#define CURRENT_VERSION "GREED/0.4"
#define GGR "http://www.public.asu.edu/~arturner/greed.tar.gz"
#define GGRS "http://www.public.asu.edu/~arturner/greed-source.tar.gz"
#define rollback 4096
int dlstat;
long dldots;
struct sockaddr_in address;
unsigned int dport;
time_t start, end;
struct URLstruct;
typedef struct URLstruct* URLp;
struct URLstruct
{       char server[512];
        char file[512];
        char name[1024];
        char filename[256];
        char user[64];
        char pass[64];
        char left[10];
        char size[10];
        char total[12];
        char cport[5];
        unsigned int port;
        int protocol;
        int sockfd;
        struct hostent *host;
        struct servent *serv;
        long long lleft;
        long long lsize;
        long long ltotal;
        FILE *fp;
        bool done;
        bool resume;
        bool retry;
} URLst;
void Download(URLp URL);
bool ReadHTTPHeader(URLp URL);
bool ReadFTPListing(URLp URL);
bool Parse(URLp URL);
bool Connect(URLp URL);
void ReadString(char *str1, int *ind, char stopchar, int stopint, char* str2
);
void ReadString(char *str1, int &ind, char stopchar, int stopint, char* str2
)
//////////////////////////////////////
//      void ReadString(char *str1, int &ind, char stopchar,
//                      int stopint, char* str2);
//
// Pre:  Assigned (str1) && Assigned (ind) && Assigned (stopchar)
//       && Assigned (stopint)
// Post: a string starting at ind and ending at (stopchar ||
//       stopint) is copied int str2
//////////////////////////////////////
{       int stringIndex = 0;
        for (; ind < stopint && str1[ind] != stopchar; ind++)
                str2 [stringIndex++] = str1[ind];
        str2 [stringIndex] = '\0';
}
bool Parse(URLp URL)
//////////////////////////////////////
//      bool Parse(URLp URL);
//
//      Parses a URL
//
// Pre:  Assigned (URL->name)
// Post: URL->name parsed, URL->(filename, file, protocol, user, pass, cport
, seerver, port)
//       set.  Returns 1 if successful.
//////////////////////////////////////
{       int at = 0;
        int i = 0;
        dlstat = 0;
        dldots = 0;
        URL->retry = 0;
        for(i = strlen(URL->name); i > 0 && URL->name[i] != '@'; i--);
        if(URL->name[i] == '@') at = i;
        if (strstr(URL->name, "http://") != NULL || strstr(URL->name, "ftp:/
/") != NULL)
        {       if(URL->name[0] == 'f')
                {       i = 6;
                        URL->protocol = FTP;
                }
                else
                {       i = 7;
                        URL->protocol = HTTP;
                }
                if (at)
                {       ReadString(URL->name, i, ':', at, URL->user);
                        i++,ReadString(URL->name, i, '\0', at, URL->pass);
                        i++;
                }
                else
                {       strcpy(URL->user, "anonymous");
                        strcpy(URL->pass, "-anonuser@anonymous.com");
                }
        } else
        {       i = 0;
                if(URL->name[0] == 'f')
                        URL->protocol = FTP;
                else
                        URL->protocol = HTTP;
        }
        at = i;
        ReadString(URL->name, i, ':', strlen(URL->name), URL->server);
        if (URL->name[i] != ':')
        {       i = at;
                ReadString(URL->name, i, '/', strlen(URL->name), URL->server
);
                if (URL->protocol == FTP)
                        strcpy (URL->cport, "21");
                else
                        strcpy (URL->cport, "80");
        }
        else
                i++,ReadString(URL->name, i, '/', strlen(URL->name), URL->cp
ort)
        ReadString(URL->name, i, '\0', strlen(URL->name), URL->file);
        for (i = strlen(URL->name); i > 0 && URL->name[i] != '/'; i--);
        i++,ReadString(URL->name, i, '\0', strlen(URL->name), URL->filename)
;
        if (URL->file[0] == '\0')
        {       strcpy (URL->file, "/");
                strcpy (URL->filename, "index.html");
        } else if (URL->file[strlen(URL->file) - 1] == '/')
                strcpy (URL->filename, "index.html");
        URL->port = atoi(URL->cport);
        return (1);
}
bool Connect(URLp URL)
//////////////////////////////////////
//
//
//
//
//////////////////////////////////////
{       URL->host = gethostbyname(URL->server);
        if (URL->host == NULL)
        {       printf("Error resolving host!\n");
                return(0);
        }
        printf("Connecting to: %s:%d\n", URL->server, URL->port);
        URL->sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (URL->sockfd == -1)
        {       printf("Error opening socket to server\n");
                return(0);
        }
        address.sin_family = AF_INET;
        address.sin_port = htons(URL->port);
        memcpy(&address.sin_addr, URL->host->h_addr, URL->host->h_length);
        if(connect(URL->sockfd, (struct sockaddr *)&address, sizeof(address)
) < 0)
        {       printf("Error in connecting to server!\n");
                return(0);
        } else
        if (URL->protocol == HTTP)
        {       write(URL->sockfd, "GET ", 4);
                write(URL->sockfd, URL->file, strlen(URL->file));
                write(URL->sockfd, " HTTP/1.1\r\nHost: ", 17);
                write(URL->sockfd, URL->server, strlen(URL->server));
                write(URL->sockfd, ":", 1);
                write(URL->sockfd, URL->cport, strlen(URL->cport));
                write(URL->sockfd, "\r\nUser-Agent: ", 14);
                write(URL->sockfd, CURRENT_VERSION, strlen(CURRENT_VERSION))
;
                write(URL->sockfd, "\r\nAccept: *.*, */*\r\n", 20);
                write(URL->sockfd, "Range: bytes=", 13);
        } else
        {       write(URL->sockfd, "USER ", 5);
                write(URL->sockfd, URL->user, strlen(URL->user));
                write(URL->sockfd, "\r\nPASS ", 7);
                write(URL->sockfd, URL->pass, strlen(URL->pass));
                write(URL->sockfd, "\r\nPASV\r\nREST 0\r\n", 16);
                write(URL->sockfd, "NOOP\r\n", 6);
                URL->resume = 1;
                if (strstr(URL->user, "anonymous") != NULL)
                        write(URL->sockfd, "LIST -L ", 8);
                else
                        write(URL->sockfd, "LIST -L ~", 9);
                write(URL->sockfd, URL->file, strlen(URL->file));
                write(URL->sockfd, "\r\n", 2);
        }
        return 1;
}
bool ReadHTTPHeader(URLp URL)
//////////////////////////////////////
//      bool ReadHTTPHeader(URLp URL)
//
//      URL->protcol == HTTP, HTTP header read.
//
// Pre:  Assigned(URL->size) && Assigned(URL->filename) && Assigned(URL->soc
kfd)
// Post: URL->fp, URL->lsize, URL->left, and URL->lleft set. Returns 1
//       if successful
//////////////////////////////////////
{       int bsize = 0;
        char *temp, *fin;
        char buffer[4096];
        int i;
        URL->done = 0;
        URL->fp = fopen (URL->filename, "a+b");
        URL->lsize = ftell(URL->fp);
        if ((URL->lsize >= URL->ltotal) && URL->ltotal != 0)
        {       printf("Error... It seems this file has already been downloa
ded..\n");
                return(0);
        } else
        if (URL->fp == NULL)
        {       printf("Error opening file %s\n", URL->filename);
                return(0);
        } else
        if (URL->lsize == -1)
                URL->lsize = 0;
        sprintf(URL->size, "%lld", URL->lsize);
        write(URL->sockfd, URL->size, strlen(URL->size));
        write(URL->sockfd, "-\r\n\r\n", 5);
        dldots = URL->lsize / rollback;
        bsize = read(URL->sockfd, buffer, sizeof(buffer) - 1);
        if (!(fin=strstr(buffer,"\r\n\r\n")))
        {       printf("Error - webserver headers too large, fatal!\n");
                return(0);
        }
        *fin='\0'; fin+=4;
        if (strstr(buffer,"Transfer-Encoding: chunked"))
        {       printf("Error - \"chunked\" Transfer-Encoding not implemente
d, II'm violating HTTP 1.1!\n");
                return(0);
        }
        if (URL->lsize && !strstr(buffer,"Content-Range:"))
        {       printf("Error - server says we already have the completed fi
le, resuming too dangerous!\n");
                return(0);
        }
        printf("Resuming from %s bytes.\r\n", URL->size);
        //NOTE: I have changed Content-Length to ength because
        //      people have notified me that some servers don't
        //      capitalize the L in length.
        temp = strstr (buffer, "ength: ");
        if (temp != NULL)
        {       for (i = 0; temp[i + 7] != '\r'; i++)
                        URL->left[i] = temp[i + 7];
                URL->left [i] = '\0';
                URL->lleft = atol(URL->left);
                if (URL->lsize == URL->lleft)
                {       printf("Error... I think that you are trying to resu
me aa file that has already been downloaded!\n");
                        return 0;
                }
                printf("%s bytes left to download!\r\n", URL->left);
                URL->resume = 1;
                URL->lleft -= (bsize-(fin-buffer));
        } else
        {       printf("Error in web site file size estimation, or unknown s
erveer type\n\n");
                URL->resume = 0;
                URL->lleft = 2000000000;
        }
        fwrite(fin,bsize-(fin-buffer),1,URL->fp);
        printf("[.");
        fflush(NULL);
        return 1;
}
bool ReadFTPListing (URLp URL)
//////////////////////////////////////
//
//
//
//////////////////////////////////////
{       int result = 1;
        int len = 1;
        int i = 0;
        int j = 0;
        int k = 0;
        int listfd = 0;
        int datafd = 0;
        char buffer[64000], buffer2[64000], buffer3[64000], buffer4[64000];
        char lhost[5][4];
        char *rbuffer = NULL;
        struct sockaddr_in datastream, liststream;
        URL->resume = 1;
        while(result > 0)
        {       result = read(URL->sockfd, buffer + len - 1, sizeof(buffer)
+ leen - 1);
                len += result;
                if (strstr(buffer, "200") != NULL)
                        result = 0;
        }
        rbuffer = strstr(buffer, "Passive Mode (");
        if (rbuffer == NULL)
        {       printf("PASV mode not supported, aborting.\n");
                exit(0);
        } else
        for (i = 14; (unsigned)i < strlen(rbuffer) && rbuffer[i] != ')'; i++
)
                if (rbuffer[i] == ',')
                {       lhost[j][k] = '\0';
                        j++;
                        k = 0;
                } else
                lhost[j][k++] = rbuffer[i];
        listfd = socket(AF_INET, SOCK_STREAM, 0);
        if (listfd == -1)
        {       printf("Error opening socket to FTP server for LIST!\n");
                return(0);
        }
        liststream.sin_family = AF_INET;
        liststream.sin_port = htons(atoi(lhost[4])*256 + atoi(lhost[5]));
        memcpy(&liststream.sin_addr, URL->host->h_addr, URL->host->h_length)
;
        if (connect(listfd, (struct sockaddr *)&liststream, sizeof(liststrea
m)) == -1)
        {       printf("Error connecting to FTP socket for LIST!\n");
                close(listfd);
                URL->retry = 1;
                return(0);
        }
        result = 1;
        len = 1;
        while(result > 0)
        {       result = read(listfd, buffer2 + len - 1, sizeof(buffer2) + l
en -- 1);
                len += result;
        }
        int whitespace = 0;
        for (j = 0; (unsigned)j < strlen(buffer2) && whitespace < 4; j++)
        {       if (buffer2[j] == ' ' && buffer2[j + 1] != ' ')
                        whitespace ++;
        }
        for (k = 0; (unsigned)j < strlen(buffer2); j++)
                if (buffer2[j] == ' ' || (buffer2[j] > ('0' - 1) && buffer2[
j] << ('9' + 1)))
                        URL->total[k++] = buffer2[j];
                else
                        j = strlen(buffer2);
        URL->total[j - 4] = '\0';
        URL->ltotal = atol(URL->total);
        printf("File size: %lld bytes\n", URL->ltotal);
        close(listfd);
        write(URL->sockfd, "PASV\r\n", 6);
        write(URL->sockfd, "REST 0\r\n", 8);
        write(URL->sockfd, "NOOP\r\n", 6);
        result = 1;
        len = 1;
        while(result > 0)
        {       result = read(URL->sockfd, buffer3 + len - 1, sizeof(buffer3
) + len - 1);
                len += result;
                if (strstr(buffer3, "200") != NULL)
                        result = 0;
        }
        rbuffer = strstr(buffer3, "Passive Mode (");
        if (rbuffer == NULL)
                return(0);
        else
                for (i = 14, j = 0, k = 0; (unsigned)i < strlen(rbuffer) &&
rbufffer[i] != ')'; i++)
                        if (rbuffer[i] == ',')
                        {       lhost[j][k] = '\0';
                                j++;
                                k = 0;
                        }
                        else
                        lhost[j][k++] = rbuffer[i];
        URL->fp = fopen (URL->filename, "a+b");
        URL->lsize = ftell(URL->fp);
        if (URL->lsize >= URL->ltotal)
        {       printf("Error... It seems this file has already been downloa
ded..\n");
                return(0);
        } else
        if (URL->fp == NULL)
        {       printf("Error opening file %s\n", URL->filename);
                return(0);
        } else
        if (URL->lsize < rollback)
                URL->lsize = 0;
        else
                URL->lsize -= rollback;
        ftruncate(fileno(URL->fp), URL->lsize);
        sprintf(URL->size, "%lld", URL->lsize);
        printf("Resuming from %s bytes.\n\n", URL->size);
        write(URL->sockfd, "TYPE I\r\n", 8);
        write(URL->sockfd, "REST ", 5);
        write(URL->sockfd, URL->size, strlen(URL->size));
        write(URL->sockfd, "\r\n", 2);
        dldots = (long long)URL->lsize / rollback;
        write(URL->sockfd, "RETR ", 5);
        write(URL->sockfd, URL->file, strlen(URL->file));
        write(URL->sockfd, "\r\n", 2);
        datafd = socket(AF_INET, SOCK_STREAM, 0);
        if (datafd == -1)
        {       printf("Error opening socket to FTP server for RETR!\n");
                URL->retry = 1;
                return(0);
        }
        datastream.sin_family = AF_INET;
        datastream.sin_port = htons(atoi(lhost[4])*256 + atoi(lhost[5]));
        memcpy(&datastream.sin_addr, URL->host->h_addr, URL->host->h_length)
;
        if (connect(datafd, (struct sockaddr *)&datastream, sizeof(datastrea
m)) == -1)
        {       printf("Error connecting to FTP socket for RETR!\n");
                close(datafd);
                URL->retry = 1;
                return(0);
        }
        result = 1; len = 1;
        while(result > 0)
        {       result = read(URL->sockfd, buffer4 + len - 1, sizeof(buffer4
) + len - 1);
                len += result;
                if (strstr(buffer4, "350") != NULL)
                        result = 0;
        }
        listfd = URL->sockfd;
        URL->sockfd = datafd;
        close (listfd);
        URL->lleft = URL->ltotal - URL->lsize;
        printf("[.");
        return (1);
}
void Download(URLp URL)
//////////////////////////////////////
//      void Download(URLp URL)
//
//      Downloads up to 4k of data from URL->sockfd and writes it to URL->fp

//
// Pre:  Assigned(URL->sockfd) && Assigned(URL->lleft) && Assigned(URL->fp)
&& UURL->done != 1
// Post: set URL->done = 1, if finished.
//////////////////////////////////////
{       int bsize = 1;
        char buff[rollback];
        bsize = read(URL->sockfd, buff, sizeof(buff));
        URL->lleft = URL->lleft - bsize;
        if (bsize > 0)
                dlstat += bsize;
        fwrite(buff, bsize, 1, URL->fp);
        if (dlstat > rollback - 1)
        {       printf(".");
                dlstat -= rollback;
                fflush(NULL);
                dldots ++;
                if (dldots%50 == 0)
                {       printf("]  -%ldk %.2fk/sec- \n[.", (rollback * dldot
s) // 1024,
                                ((float)((rollback * 50) / 1024))
                                 / ((float)(time((time_t *)0) - start)));
                        start = time((time_t *)0);
                }
        }
        if ((bsize < 1) || (URL->lleft < 1 && URL->resume))
        {       if (dldots%50 == 0)
                        printf("] -%ldk %.2fk/sec-\n\nChecking Completion St
atuss...\n",
                                (rollback * dldots)/1024,
                                ((float)((rollback * 1) / 1024)) /
                                 ((float)(time((time_t *)0) - start)));
                else
                        printf("] -%ldk %.2fk/sec-\n\nChecking Completion St
atuss...\n",
                                (rollback * dldots)/1024,
                                ((float)((rollback * (dldots%50)) / 1024)) /

                                 ((float)(time((time_t *)0) - start)));
                close(URL->sockfd);
                fclose(URL->fp);
                URL->done = 1;
                printf("%s Done!\n\n", URL->filename);
        }
}
int main (int argc, char *argv[])
//////////////////////////////////////
//
//
//
//
//////////////////////////////////////
{       URLp URL = &URLst;
        int i;
        printf("%s  [Get and Resume Elite EDition] - By Anoakie Turner\r\n",
 CURRRENT_VERSION);
        for (i = 1; i < argc; i ++)
                if (argv[i][0] == '-')
                {       if (argv[i][1] == 'n' || argv[i][1] == 'N')
                        {       argv[i] = GGR;
                        } else
                        {       printf("\n\nUSEAGE: greed URL(1) URL(2) ...
URL((N)\n");
                                printf("i.e.: greed %s ftp://some.where/out/
therre.tar.gz\n", GGR);
                                exit(0);
                        }
                }
        for (i = 1; i < argc; i ++)
        {       strcpy(URL->name, argv[i]);
                if (Parse(URL))
                if (Connect(URL))
                if ((URL->protocol == HTTP && ReadHTTPHeader(URL)) ||
                    (URL->protocol == FTP && ReadFTPListing(URL)))
                {       start = time((time_t *)0);
                        while (!URL->done)
                                Download(URL);
                }
                close (URL->sockfd);
                if (URL->retry == 1)
                {       URL->retry = 0;
                        i--;
                        printf("Retrying in 5 seconds...\n");
                        sleep(5);
                }
        }
        return(EXIT_SUCCESS);
}

--
--
※ 转寄:·UNIX编程 apue.dhs.org·[FROM: 210.39.3.50]
--
※ 转载:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 192.168.0.146]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店