项目一部分需要使用socket写http协议,并下载文件,看似简单得问题,调试起来确有一些小小得问题,如果是windows平台的话,自然会简单很多,一个DownloadFile API就可以搞定,可是客户得Proj是在Linux下,不得已,从头开发了。目前得代码由于依然在win下面调试,所以移植得时候稍微注意一下就可以了。
看代码:
看代码:
- #include <string>
- #include <iostream>
- #include <stdio.h>
- #include <winsock.h>
- #include <conio.h>
- using namespace std;
- #pragma comment("ws2_32.lib")
- string host2ip(const string& strdomain);
- void save2file(char *buffer,const string& filename);
- int getlength(const string& sheader);
- bool getstatus(const string& sheader);
- int getleftlength(const string& sheader);
- void sethttphead(const string& file,const string& server);
- int port = 80;
- int error=0;
- string serveraddr;
- int i = 0;
- const int BUFFER_SIZE = 1024;
- char buffer[BUFFER_SIZE] = {0};
- char msg[BUFFER_SIZE];
- FILE *f;
- const string file = "/BT/200801/3/117906.torrent";
- const string url = "www.supbt.com";
- const string filename = "117906.torrent";
- int main(void)
- {
- int r;
- WSADATA wsa;
- SOCKET sock;
- struct sockaddr_in sin;
- f = fopen(filename.c_str(),"ab");
- sethttphead(file,url);
- if(WSAStartup(MAKEWORD(2,2),&wsa))
- {
- printf("WSAStartup Error: %d/n",WSAGetLastError());
- getche();
- return -1;
- }
- if((sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==INVALID_SOCKET)
- {
- printf("Socket Error: %d/n",WSAGetLastError());
- getche();
- return -1;
- }
- sin.sin_family=AF_INET;
- sin.sin_port=htons(port);
- serveraddr = host2ip(url);
- cout << serveraddr << endl;
- sin.sin_addr.s_addr=inet_addr(serveraddr.c_str());
- if(connect(sock,(struct sockaddr *)&sin,sizeof(sin))==SOCKET_ERROR)
- {
- printf("Connect Error: %d/n",WSAGetLastError());
- printf("请检测网络连接!/n");
- getche();
- return -1;
- }
- if((r=send(sock,msg,sizeof(msg),0))==SOCKET_ERROR)
- {
- printf("Send Error: %d/n",WSAGetLastError());
- getche();
- return -1;
- }
- memset(buffer,0,BUFFER_SIZE);
- if((r=recv(sock,buffer,BUFFER_SIZE,0))==SOCKET_ERROR)
- {
- printf("Recv Error: %d/n",WSAGetLastError());
- closesocket(sock);
- return -1;
- }
- string header = string(buffer);
- int ilength = getlength(header);
- int leftlength = ilength;
- int icount;
- if(getstatus(header)){
- //current is r
- char *q = buffer;
- char *p = strstr(buffer, "/r/n/r/n");
- p += 4;
- //注意这里得 r - (p-q) 非常关键得问题
- fwrite(p,r - (p - q),1,f);
- leftlength -= r - (p - q);
- int i=0;
- icount = r - (p - q);
- while(true)
- {
- memset(buffer, 0, BUFFER_SIZE);
- r = recv(sock, buffer, BUFFER_SIZE, 0);
- if (r < 0) {
- closesocket(sock);
- return 2;
- }
- if (r == 0) {
- break;
- }
- int tmp;
- tmp = leftlength; //209 100 100 92
- leftlength -= r;
- if(leftlength > 0){
- fwrite(buffer,r,1,f);
- icount += r;
- }
- else if(leftlength == 0){
- //
- break;
- }
- else{
- icount += tmp;
- fwrite(buffer,tmp,1,f);
- break;
- }
- cout << i++ << " r is "<< r << endl;
- }
- }else{
- cout << "http protocal error" << endl;
- }
- cout << icount << endl;
- fclose(f);
- closesocket(sock);
- WSACleanup();
- getche();
- return 0;
- }
- /*
- 构造HTTP头
- */
- void sethttphead(const string& file,const string& server)
- {
- strcat(msg,"GET ");
- strcat(msg,file.c_str());
- strcat(msg," HTTP/1.1");
- strcat(msg,"/r/n");
- strcat(msg,"Accept:*/*");
- strcat(msg,"/r/n");
- //strcat(msg,"Accept-Language: zh-cn");
- //strcat(msg,"/r/n");
- //strcat(msg,"Accept-Encoding: gzip, deflate");
- //strcat(msg,"/r/n");
- strcat(msg,"User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)");
- strcat(msg,"/r/n");
- strcat(msg,"Host:");
- strcat(msg,server.c_str());
- strcat(msg,"/r/n");
- strcat(msg,"Connection: Keep-Alive");
- strcat(msg,"/r/n");
- strcat(msg,"/r/n");
- }
- //---------------------------------------------------------------------------
- /*
- 将domain 转换为IP地址
- */
- string host2ip(const string& strdomain)
- {
- SOCKADDR_IN saddr;
- WORD wVersionRequested;
- WSADATA wsaData;
- hostent *pHostIp;
- int nErrorNum;
- wVersionRequested = MAKEWORD(2, 2);
- nErrorNum = WSAStartup(wVersionRequested, &wsaData);
- if(nErrorNum != 0)
- {
- return "";
- }
- saddr.sin_family = AF_INET;
- pHostIp = gethostbyname(strdomain.c_str());
- if(pHostIp == NULL)
- {
- return "0.0.0.0";
- }
- WSACleanup();
- return (string)inet_ntoa(*(LPIN_ADDR)*(pHostIp->h_addr_list));
- }
- /*
- 该方法为测试用法,并为应用到项目中
- */
- void save2file(char *buffer,const string& filename)
- {
- FILE *f;
- f = fopen(filename.c_str(),"a+");
- fwrite(buffer,strlen(buffer),1,f);
- fclose(f);
- }
- /*
- 该方法获取待下载文件大小
- */
- int getlength(const string& sheader){
- char * cont_len_pos;
- unsigned long cont_length;
- const char* header = sheader.c_str();
- cont_len_pos =(char *)strstr(header,"Content-Length:");
- cont_len_pos = (char *)strchr(cont_len_pos,' ');
- cont_len_pos++;
- sscanf(cont_len_pos, "%ld", &cont_length);
- return cont_length;
- }
- /*
- 该方法判断是否Get成功,不成功就取消下载文件
- */
- bool getstatus(const string& sheader){
- string start = "HTTP/1.1 200 OK";
- if(sheader.find(start,0) != string::npos){
- return true;
- }
- else{
- return false;
- }
- }
- /*
- 该方法并没有用到,开始考虑多了
- */
- int getleftlength(const string& sheader){
- int nreturnl = 0;
- int ilength = sheader.length();
- string _send = "/r/n/r/n";
- int istart = sheader.find_last_of(_send);
- if(istart != string::npos){
- nreturnl = ilength - istart -_send.length();
- }
- return nreturnl;
- }