C语言 HTTP协议下载文件,实现断点续传,socket通讯,目前只支持ip和port方式连接,有兴趣的读者可完善域名方式。
代码分为 http.c: 实现http协议下载文件 ,socket.c: 封装linux socket函数,移植时只需修改socket.c中的函数即可。
希望对大家有帮助,本人亲测可用!
http.c
点击(此处)折叠或打开
- //http.c
- //作者:王振
- #include <stdio.h>
- #include <stdlib.h>
- #include <errno.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include "socket.h"
- #include "http.h"
- #define MAX_RECV_SIZE 1440//硬件单包最大的接收字节数
- char g_host[URL_LEN];
- char g_ip[URL_LEN+1];//ip/域名
- char g_port[5+1];
- char g_buf_send[4*1024];//发送数据暂存区
- char g_buf_recv[10*1024];//接收数据暂存区
- BreakPoint_ST g_break_point;
- /*
- 功能:判断断点有效性,现在校验url是否一致
- 参数:
- 返回:
- >0---------有效,已下载文件大小
- -1----------无效
- */
- int Get_Breakpoint_Available(BreakPoint_ST *breakpoint,char *url,char *file_crc)
- {
- //判断断点是否有效,后续加入文件校验码
- if((memcmp(breakpoint->url,url,strlen(url))== 0)&&(breakpoint->recv_size== MAX_RECV_SIZE))
- return breakpoint->download_size;
- else
- {
- return -1;
- }
- }
- /*
- 功能:判断要下载文件是否存在断点
- 参数:
- filename---要下载的文件名
- file_crc----服务器返回下载文件的校验码
- 返回:
- 0---------无断点
- >0--------有断点,已下载文件大小
- */
- int Get_Breakpoint(char *url,char *filename,char *file_crc)
- {
- char filename_bp[64];
- int fd = -1;
- int ret;
- BreakPoint_ST break_point;
- //断点文件名 filename+bp
- sprintf(filename_bp,"%s.bp",filename);
- //检测是否存在filename断点文件
- fd = open(filename_bp,O_RDONLY,S_IRUSR|S_IWUSR);
- if(fd == -1)
- {
- #ifdef DEBUG_HTTP
- printf("no exsit %s
",filename_bp);
- #endif
- return 0;
- }
- //存在断点
- ret = read(fd,&break_point,sizeof(break_point));
- if(ret != sizeof(break_point))
- {
- perror("ERR:Get_Breakpoint read");
- exit(-1);
- }
- close(fd);
- //判断断点是否有效
- ret = Get_Breakpoint_Available(&break_point,url,file_crc);
- if(ret > 0)
- return ret;
- else
- {
- printf("%s not available
",filename_bp);
- remove(filename);
- remove(filename_bp);
- return 0;
- }
- }
- /*
- 功能:保存断点信息,文件名filename.bp
- 参数:
- filename---要下载的文件名
- file_crc----服务器返回下载文件的校验码
- 返回:
- 0---------成功
- >0--------有断点,已下载文件大小
- */
- int Save_Breakpoint(char *url,char *filename,int download_size,char *file_crc)
- {
- int fd;
- BreakPoint_ST breakpoint;
- char filename_bp[128];//断点信息文件名,包含路径
- sprintf(filename_bp,"%s.bp",filename);
- /* 创建目的文件 */
- if((fd=open(filename_bp,O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR))==-1)
- {
- fprintf(stderr,"Open %s Error:%s
",filename_bp,strerror(errno));
- exit(1);
- }
- memset(&breakpoint,0x0,sizeof(breakpoint));
- strcpy(breakpoint.url,url);
- //strcpy(breakpoint.crc,file_crc);
- strcpy(breakpoint.filename,filename);
- breakpoint.download_size = download_size;
- breakpoint.recv_size= MAX_RECV_SIZE;
- //xu tioa zheng wei fen ci xie ru
- if(write(fd,&breakpoint,sizeof(breakpoint)) != sizeof(breakpoint))
- {
- perror("ERR:Save_Breakpoint");
- exit(1);
- }
- close(fd);
- return 0;
- }
- /*
- 功能:保存文件,追加写
- 参数:
- 返回:
- 0---------成功
- */
- int Save_File(char *filebuf,int filelength,char *filename)
- {
- int fd;
- /* 创建目的文件追加写 */
- if((fd=open(filename,O_WRONLY|O_CREAT|O_APPEND,S_IRUSR|S_IWUSR))==-1)
- {
- fprintf(stderr,"Open %s Error:%s
",filename,strerror(errno));
- exit(1);
- }
- //xu tioa zheng wei fen ci xie ru
- if(write(fd,filebuf,filelength) != filelength)
- {
- perror("ERR:Save_File");
- exit(1);
- }
- close(fd);
- return 0;
- }
- int HTTP_GetResponseCode(void)
- {
- }
- /*
- 功能:读取http返回的协议实体主体长度
- 参数:
- revbuf--------接收到的返回值
- 返回值:
- >=0---------内容(实体主体)的长度
- -1-----------数据返回错误
- */
- int HTTP_GetRecvLength(char *revbuf)
- {
- char *p1 = NULL;
- int HTTP_Body = 0;//内容体长度
- int HTTP_Head = 0;//HTTP 协议头长度
- HTTP_Body = HTTP_GetContentLength(revbuf);
- if(HTTP_Body == -1)
- return -1;
- p1=strstr(revbuf,"
");
- if(p1==NULL)
- return -1;
- else
- {
- HTTP_Head = p1- revbuf +4;// 4是
的长度
- return HTTP_Body+HTTP_Head;
- }
- }
- /*
- 功能:读取http返回的Content-Length长度
- 参数:
- revbuf--------接收到的数据
- 返回值:
- >=0---------Content-Length长度
- -1-----------数据返回错误
- */
- int HTTP_GetContentLength(char *revbuf)
- {
- char *p1 = NULL, *p2 = NULL;
- int HTTP_Body = 0;//内容体长度
- p1 = strstr(revbuf,"Content-Length");
- if(p1 == NULL)
- return -1;
- else
- {
- p2 = p1+strlen("Content-Length")+ 2;
- HTTP_Body = atoi(p2);
- return HTTP_Body;
- }
- }
- /*
- 功能:
- 参数:
- sockfd--------接收到的返回值
- 返回值:
- >0---------接收到长度
- -1----------失败
- =0---------服务端断开连接
- 注:内部接收缓冲10k
- */
- int HTTP_Recv(int sockfd,char *buf_recv)
- {
- int ret;
- int recvlen=0;
- int downloadlen = 0;
- //int contentlen=0;
- char buf_recv_tmp[10*1024+1];
- memset(buf_recv_tmp,0x0,sizeof(buf_recv_tmp));
- while(1)
- {
- ret = Recv(sockfd,buf_recv_tmp+recvlen,sizeof(buf_recv_tmp)-1,0);
- if(ret <= 0)//下载失败
- {
- perror("ERR:recv fail");
- return ret;
- }
- if(recvlen == 0)
- {
- #ifdef DEBUG_HTTP_RECV
- printf("recv len = %d
", ret);
- printf("recv = %s
", buf_recv_tmp);
- #endif
- //获取需要下载长度;
- downloadlen = HTTP_GetRecvLength(buf_recv_tmp);
- #ifdef DEBUG_HTTP_RECV
- printf("downloadlen = %d
",downloadlen);
- #endif
- }
- recvlen += ret;
- #ifdef DEBUG_HTTP_RECV
- printf("total recvlen = %d
",recvlen);
- #endif
- if(downloadlen == recvlen)//下载完成
- break;
- }
- memcpy(buf_recv,buf_recv_tmp,downloadlen);
- return recvlen;
- }
- /*
- 功能:获取下载url中的文件名,最后一个/后的字符
- 参数:
- 返回值:
- 0-----------成功
- -1----------失败
- 注:内部接收缓冲10k
- */
- int HTTP_GetFileName(char *url,char *filename)
- {
- //提取url中最后一个/后的内容
- int len;
- int i;
- len = strlen(url);
- for(i=len-1;i>0;i--)
- {
- if(url[i] == '/')
- break;
- }
- if(i == 0)//下载地址错误
- {
- printf("url not contain '/'
");
- return -1;
- }
- else
- {
- strcpy(filename,url+i+1);
- #ifdef DEBUG_HTTP
- printf("filename=%s
",filename);
- #endif
- return 0;
- }
- }
- /*
- 功能:获取下载url中的路径,第一个/后的字符
- 参数:
- 返回值:
- 0-----------成功
- -1----------失败
- 注:url ex "http://host:port/path"
- */
- int HTTP_GetPath(char *url,char *path)
- {
- char *p;
- p = strstr(url,"http://");
- if(p == NULL)
- {
- p = strchr(url,'/');
- if(p == NULL)
- return -1;
- else
- {
- strcpy(path,p);
- return 0;
- }
- }
- else
- {
- p = strchr(url+strlen("http://"),'/');
- if(p == NULL)
- return -1;
- else
- {
- strcpy(path,p);
- return 0;
- }
- }
- }
- /*
- 功能:获取下载url中的ip和port,ip支持域名,端口默认为80
- 参数:
- 返回值:
- 1-----------域名式
- 2-----------ip port式
- -1----------失败
- 注:url ex "http://host:port/path"
- */
- int HTTP_Get_IP_PORT(char *url,char *ip,char *port)
- {
- char *p = NULL;
- int offset = 0;
- char DOMAIN_NAME[128];
- p = strstr(url,"http://");
- if(p == NULL)
- {
- offset = 0;
- }
- else
- {
- offset = strlen("http://");
- }
- p = strchr(url+offset,'/');
- if(p == NULL)
- {
- printf("url:%s format error
",url);
- return -1;
- }
- else
- {
- memset(DOMAIN_NAME,0x0,sizeof(DOMAIN_NAME));
- memcpy(DOMAIN_NAME,url+offset,(p-url-offset));
- p = strchr(DOMAIN_NAME,':');
- if(p == NULL)
- {
- strcpy(ip,DOMAIN_NAME);
- strcpy(port,"80");
- //printf("ip %p,port %p
",ip,port);
- #ifdef DEBUG_HTTP
- printf("ip=%s,port=%s
",ip,port);//debug info
- #endif
- return 1;
- }
- else
- {
- *p = '