先在本机建一个网站,启用,然后就可以测试了。
遇到问题:
http请求头中要选择非可持续连接,如果不写这一行while中recv()会一直持续等待输入。(个人理解,没查资料,不知道对不对)
//HTTPClient.h文件
#ifndef HTTPClient_H_
#define HTTPClient_H_
#include <string>
#include <winsock.h>
#include <iostream>
#include <fstream>
#pragma comment(lib,"ws2_32.lib")
//#define tempDirectory "c:\\"
using namespace std;
class HTTPClient
{
public:
HTTPClient(void);
~HTTPClient(void);
bool HTTPClient::DownloadFile(SOCKET parmSock,string serverName, string sourcePath, string fileName, string localDirectory,string port);
};
#endif
//HTTPClient.cpp文件
#include "HTTPClient.h"
HTTPClient::HTTPClient(void)
{
}
HTTPClient::~HTTPClient(void)
{
}
//for example serverName = "127.0.0.1" or "localhost"
// sourcePath = "/abc/"
// fileName = "config.xml"
// localDirectory = "c:\\"
bool HTTPClient::DownloadFile(SOCKET parmSock,string serverName, string sourcePath, string fileName, string localDirectory,string port)
{
ofstream fout;
string newfile = localDirectory + fileName;
//识别中文路径和文件名
std::locale::global(std::locale(""));
fout.open(newfile.c_str(),ios_base::binary);
if(!fout.is_open())
{
cout<<"open newfile error!"<<endl;
}
char szBuffer[1024];
//将目录和文件名中的' '转换为"%20"
//sourcePath
int npos = sourcePath.find(" ");
while(npos + 1)
{
npos = sourcePath.find(" ");
if(npos == -1)
break;
sourcePath.replace(npos,strlen(" "),"%20");
}
//fileName
npos = fileName.find(" ");
while(npos + 1)
{
npos = fileName.find(" ");
if(npos == -1)
break;
fileName.replace(npos,strlen(" "),"%20");
}
string requestFile = sourcePath + fileName;
///
//格式化http头
//第一行
sprintf(szBuffer,"GET %s HTTP/1.1\r\n",requestFile.c_str());
//第二行
strcat(szBuffer,"Host:");
strcat(szBuffer,serverName.c_str());
strcat(szBuffer,":");
strcat(szBuffer,port.c_str());
strcat(szBuffer,"\r\n");
//第三行
//strcat(szBuffer,"Accept:*/*");
/*strcat(szBuffer,"\r\n");
//
//第四行(可有可无)
strcat(szBuffer,"User-Agent:GeneralDownloadApplication");
strcat(szBuffer,"\r\n");
*/
//第五行 非持久连接
strcat(szBuffer,"Connection:close");
strcat(szBuffer,"\r\n");
//最后一行
strcat(szBuffer,"\r\n");
int nRet = send(parmSock, szBuffer, strlen(szBuffer), 0);
if (nRet == SOCKET_ERROR)
{
cout<<"send() error"<<endl;
closesocket(parmSock);
return false;
}
//
// Receive the file contents and print to stdout
//
///
//取出http头,大小应该不超过1024个字节,只在第一次接收时进行处理
///
nRet = recv(parmSock, szBuffer, sizeof(szBuffer), 0);
if (nRet == SOCKET_ERROR)
{
cout<<"recv() error"<<endl;
closesocket(parmSock);
fout.close();
WSACleanup();
return false;
}
//
//判断该文件是否存在
std::string strBuffer = szBuffer;
std::string firstString = strBuffer.substr(0,strBuffer.find("\r\n"));
int File_Exist = firstString.find("200");
if(File_Exist == -1)
{
cout<<"File not found in the web."<<endl;
return false;
}
//获取文件内容开始位置
int i = 0;
while(1)
{
if((szBuffer[i]=='\r')&&(szBuffer[i+1]=='\n')&&(szBuffer[i+2]=='\r')&&(szBuffer[i+3]=='\n'))
{
break;
}
i++;
}
//文件内容开始
int fileBegin = i+4;
/
for(i = fileBegin; i < nRet; i++)
{
fout.write(&szBuffer[i],sizeof(szBuffer[i]));
}
/*static int count = 0;
count += nRet - fileBegin;
*/
while(1)
{
// Wait to receive, nRet = NumberOfBytesReceived
nRet = recv(parmSock, szBuffer, sizeof(szBuffer), 0);
if (nRet == SOCKET_ERROR)
{
cout<<"recv() error"<<endl;
closesocket(parmSock);
fout.close();
WSACleanup();
return false;
}
/
//cout<<"\nrecv() returned "<<nRet<<" bytes"<<endl;
if (nRet == 0)
break;
// Write to stdout
count += nRet;
fout.write(szBuffer,nRet);
}
closesocket(parmSock);
fout.close();
WSACleanup();
return true;
}
//main.cpp文件
#include "HTTPClient.h"
//#include <iostream>
int main()
{
HTTPClient m;
//m.DownloadFile("localhost","/abc/","config.xml","D:\\");
std::string url = "http://localhost/Water lilies.jpg";
std::string localDirectory = "D:\\中 国\\";
std::string port = "5550";
// cout<<m.ContentLengthInt<<endl;
// cout<<m.RangeInt<<endl;
///
std::string removeProtocol;
std::string serverName;
std::string sourcePath;
std::string fileName;
int ret;
ret = url.find("http://");
if(ret != -1)
{
removeProtocol = url.substr(strlen("http://"));
}
else
{
removeProtocol = url;
}
/* ret = url.find("https://");
if(ret != -1)
{
removeProtocol = url.substr(strlen("https://"));
}
else
{
removeProtocol = url;
}
*/
ret = removeProtocol.find_first_of('/');
serverName = removeProtocol.substr(0,ret);
int net = removeProtocol.find_last_of('/');
sourcePath = removeProtocol.substr(ret,net-ret+1);
fileName = removeProtocol.substr(net+1);
//
WSADATA wsaData;
int nRet;
//
// Initialize WinSock.dll
//
nRet = WSAStartup(0x101, &wsaData);
if (nRet)
{
WSACleanup();
return false;
}
if (wsaData.wVersion != 0x101)
{
WSACleanup();
return false;
}
IN_ADDR iaHost;
LPHOSTENT lpHostEntry;
iaHost.s_addr = inet_addr(serverName.c_str());
if (iaHost.s_addr == INADDR_NONE)
{
// Wasn't an IP address string, assume it is a name
lpHostEntry = gethostbyname(serverName.c_str());
}
else
{
// It was a valid IP address string
lpHostEntry = gethostbyaddr((const char *)&iaHost,
sizeof(struct in_addr), AF_INET);
}
if (lpHostEntry == NULL)
{
cout<<"gethostbyname() error"<<endl;
return false;
}
//
// Create a TCP/IP stream socket
//
SOCKET parmSock;
parmSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (parmSock == INVALID_SOCKET)
{
cout<<"socket() error"<<endl;
return false;
}
//
// Find the port number for the HTTP service on TCP
//
LPSERVENT lpServEnt;
SOCKADDR_IN saServer;
lpServEnt = getservbyname("http", "tcp");
if (lpServEnt == NULL)
saServer.sin_port = htons(80);
else
saServer.sin_port = lpServEnt->s_port;
//
// Fill in the rest of the server address structure
//
saServer.sin_family = AF_INET;
saServer.sin_addr = *((LPIN_ADDR)*lpHostEntry->h_addr_list);
//
// Connect the socket
//
nRet = connect(parmSock, (LPSOCKADDR)&saServer, sizeof(SOCKADDR_IN));
if (nRet == SOCKET_ERROR)
{
cout<<"connect() error"<<endl;
closesocket(parmSock);
return false;
}
//
m.DownloadFile(parmSock,serverName,sourcePath,fileName,localDirectory,port);
system("pause");
return 0;
}