1、为了支持断点,下载一个文件(假设Server不支持keep-alive)需要首先发请求得到Server上该文件的大小,并发出下载文件的请求,让server从某位置开始下载(又假设server是支持断点的)即有两次请求.-----不知有没这个必要?
2、想进行Socket的编程的学习,从CAsyncSocket派生一个类CHttpAsyncSocket,我的代码如下:
//在CHttpAsyncSocket头文件定义一下当前下载状态
typedef enum { CONNECT_NONE = 0, CONNECT_FILEINFO = 1, RECEIVE_FILEINFO = 2, CONNECT_DOWNLOAD = 3, RECEIVE_DOWNLOAD = 4} DOWNLOADSTATUS;
DOWNLOADSTATUS m_dsCurStatus; //在CHttpAsyncSocket类实现代码 //连接server
void CHttpAsyncSocket::BeginDownload()
{
//连接Server
if(Connect(m_strServerIP, m_nServerPort) == SOCKET_ERROR)
{
Close(); m_dsCurStatus = CONNECT_NONE;
}
else
{
m_dsCurStatus = CONNECT_FILEINFO;
}
} //连接成功,则发送得到文件大小或下载文件请求
void CHttpAsyncSocket::OnConnect(int nErrorCode)
{
CAsyncSocket::OnConnect(nErrorCode);
if (nErrorCode)
{
Close();
m_dsCurStatus = CONNECT_NONE;
}
else if(m_dsCurStatus == CONNECT_FILEINFO) //请求得到Server上的文件大小、是否支持断点续传等
{
CString strSend;
strSend.Format( "GET %s HTTP/1.1\r\n"
"Host: %s:%d\r\n"
"Accept: */*\r\n"
"Pragma: no-cache\r\n"
"Cache-Control: no-cache\r\n"
"Connection: close\r\n"
"Range: bytes=100-\r\n"
"\r\n",
m_strFileUrl, m_strServerIP, m_nServerPort); int ret = Send(strSend.GetBuffer(0), strSend.GetLength());
if(ret == SOCKET_ERROR)
{
Close(); m_dsCurStatus = CONNECT_NONE; return;
}
else
{
m_dsCurStatus = RECEIVE_FILEINFO;
}
}
else if(m_dsCurStatus == CONNECT_DOWNLOAD) //请求server从断点处下载文件
{
CString strSend;
strSend.Format( "GET %s HTTP/1.1\r\n"
"Host: %s:%d\r\n"
"Accept: */*\r\n"
"Pragma: no-cache\r\n"
"Cache-Control: no-cache\r\n"
"Connection: close\r\n"
"Range: bytes=%d-%d\r\n"
"\r\n",
m_strFileUrl, m_strServerIP, m_nServerPort, m_dwLocalFileSize, m_dwServerFileSize);
//m_dwLocalFileSize, m_dwServerFileSize分别为该文件本地大小和server上的大小 int ret = Send(strSend.GetBuffer(0), strSend.GetLength()); if(ret == SOCKET_ERROR)
{
Close(); m_dsCurStatus = CONNECT_NONE;
}
else
{
m_dsCurStatus = RECEIVE_DOWNLOAD;
m_bAlreadyGetHeader = FALSE; //http包头解出来标志
}
}
else
{
ASSERT(FALSE);
}
} //接收数据,
const int MAX_RECV_BUFFER = 1024; void CHttpAsyncSocket::OnReceive(int nErrorCode)
{
CAsyncSocket::OnReceive(nErrorCode); char szReadBuf[MAX_RECV_BUFFER];
ZeroMemory(szReadBuf, MAX_RECV_BUFFER); if (nErrorCode)
{
Close();
m_dsCurStatus = CONNECT_NONE;
}
if(m_dsCurStatus == RECEIVE_FILEINFO) //得到文件大小、是否支持断点等信息
{
m_dwServerFileSize = 0;
BOOL bSupportResume = FALSE; if(ParseHttpHeader(&m_dwServerFileSize, &bSupportResume) == TRUE) //解析返回来得http包头
{
Close(); //关闭以前建立的socket连接,问,能否再继续发下载请求?会不会乱?
Create(); //创建新的socket
//连接Server
if(Connect(m_strServerIP, m_nServerPort) == SOCKET_ERROR)
{
Close(); m_dsCurStatus = CONNECT_NONE;
}
else
{
m_dsCurStatus = CONNECT_DOWNLOAD;
}
}
else
{
Close(); m_dsCurStatus = CONNECT_NONE;
}
}
else if(m_dsCurStatus == RECEIVE_DOWNLOAD)
{
//打开本地文件,准备接受数据
CFile file;
int bOpenSuc = file.Open(m_strLocalFile, CFile::modeCreate | CFile::modeWrite | CFile::modeNoTruncate | CFile::typeBinary | CFile::shareExclusive); if(bOpenSuc == FALSE)
{
TRACE("Error in file open!\n");
Close(); m_dsCurStatus = CONNECT_NONE;
}
file.SeekToEnd(); int ret = 0, nHeadLength = 0; if(m_bAlreadyGetHeader == FALSE)
{
//去掉包头,达到包体
do
{
ret = Receive(szReadBuf, MAX_RECV_BUFFER);
nHeadLength = GetHeadLength(szReadBuf);
}while(ret <= nHeadLength);
if(ret > nHeadLength)
{
file.Write(szReadBuf + nHeadLength, ret - nHeadLength);
}
m_bAlreadyGetHeader = TRUE; //由于是异步调用OnReceive,所以后面就不用再去掉包头了
} while(TRUE)
{
ZeroMemory(szReadBuf,MAX_RECV_BUFFER);
int num = Receive(szReadBuf, MAX_RECV_BUFFER); if(num == 0 || num == SOCKET_ERROR) //下载结束或网络错误
{
if (GetLastError() != WSAEWOULDBLOCK && num == 0)
{
file.Close(); //注,下载文件几十K或几百K,老会进入这个!就在也没有响应了!不知为什么!!!
return; //难道要用定时器再连接发请求?有方法控制一下吗?
}
break;
} file.Write(szReadBuf, num);
} file.Close();
}
}
else
{
ASSERT(FALSE);
}
}贴了很多代码,不好意思,我刚学socket网络编程,哪位指导一下我这个迷途小程序员....,给个用CAsyncSocket编http下载的程序也行的(是支持断点的就更好了)
2、想进行Socket的编程的学习,从CAsyncSocket派生一个类CHttpAsyncSocket,我的代码如下:
//在CHttpAsyncSocket头文件定义一下当前下载状态
typedef enum { CONNECT_NONE = 0, CONNECT_FILEINFO = 1, RECEIVE_FILEINFO = 2, CONNECT_DOWNLOAD = 3, RECEIVE_DOWNLOAD = 4} DOWNLOADSTATUS;
DOWNLOADSTATUS m_dsCurStatus; //在CHttpAsyncSocket类实现代码 //连接server
void CHttpAsyncSocket::BeginDownload()
{
//连接Server
if(Connect(m_strServerIP, m_nServerPort) == SOCKET_ERROR)
{
Close(); m_dsCurStatus = CONNECT_NONE;
}
else
{
m_dsCurStatus = CONNECT_FILEINFO;
}
} //连接成功,则发送得到文件大小或下载文件请求
void CHttpAsyncSocket::OnConnect(int nErrorCode)
{
CAsyncSocket::OnConnect(nErrorCode);
if (nErrorCode)
{
Close();
m_dsCurStatus = CONNECT_NONE;
}
else if(m_dsCurStatus == CONNECT_FILEINFO) //请求得到Server上的文件大小、是否支持断点续传等
{
CString strSend;
strSend.Format( "GET %s HTTP/1.1\r\n"
"Host: %s:%d\r\n"
"Accept: */*\r\n"
"Pragma: no-cache\r\n"
"Cache-Control: no-cache\r\n"
"Connection: close\r\n"
"Range: bytes=100-\r\n"
"\r\n",
m_strFileUrl, m_strServerIP, m_nServerPort); int ret = Send(strSend.GetBuffer(0), strSend.GetLength());
if(ret == SOCKET_ERROR)
{
Close(); m_dsCurStatus = CONNECT_NONE; return;
}
else
{
m_dsCurStatus = RECEIVE_FILEINFO;
}
}
else if(m_dsCurStatus == CONNECT_DOWNLOAD) //请求server从断点处下载文件
{
CString strSend;
strSend.Format( "GET %s HTTP/1.1\r\n"
"Host: %s:%d\r\n"
"Accept: */*\r\n"
"Pragma: no-cache\r\n"
"Cache-Control: no-cache\r\n"
"Connection: close\r\n"
"Range: bytes=%d-%d\r\n"
"\r\n",
m_strFileUrl, m_strServerIP, m_nServerPort, m_dwLocalFileSize, m_dwServerFileSize);
//m_dwLocalFileSize, m_dwServerFileSize分别为该文件本地大小和server上的大小 int ret = Send(strSend.GetBuffer(0), strSend.GetLength()); if(ret == SOCKET_ERROR)
{
Close(); m_dsCurStatus = CONNECT_NONE;
}
else
{
m_dsCurStatus = RECEIVE_DOWNLOAD;
m_bAlreadyGetHeader = FALSE; //http包头解出来标志
}
}
else
{
ASSERT(FALSE);
}
} //接收数据,
const int MAX_RECV_BUFFER = 1024; void CHttpAsyncSocket::OnReceive(int nErrorCode)
{
CAsyncSocket::OnReceive(nErrorCode); char szReadBuf[MAX_RECV_BUFFER];
ZeroMemory(szReadBuf, MAX_RECV_BUFFER); if (nErrorCode)
{
Close();
m_dsCurStatus = CONNECT_NONE;
}
if(m_dsCurStatus == RECEIVE_FILEINFO) //得到文件大小、是否支持断点等信息
{
m_dwServerFileSize = 0;
BOOL bSupportResume = FALSE; if(ParseHttpHeader(&m_dwServerFileSize, &bSupportResume) == TRUE) //解析返回来得http包头
{
Close(); //关闭以前建立的socket连接,问,能否再继续发下载请求?会不会乱?
Create(); //创建新的socket
//连接Server
if(Connect(m_strServerIP, m_nServerPort) == SOCKET_ERROR)
{
Close(); m_dsCurStatus = CONNECT_NONE;
}
else
{
m_dsCurStatus = CONNECT_DOWNLOAD;
}
}
else
{
Close(); m_dsCurStatus = CONNECT_NONE;
}
}
else if(m_dsCurStatus == RECEIVE_DOWNLOAD)
{
//打开本地文件,准备接受数据
CFile file;
int bOpenSuc = file.Open(m_strLocalFile, CFile::modeCreate | CFile::modeWrite | CFile::modeNoTruncate | CFile::typeBinary | CFile::shareExclusive); if(bOpenSuc == FALSE)
{
TRACE("Error in file open!\n");
Close(); m_dsCurStatus = CONNECT_NONE;
}
file.SeekToEnd(); int ret = 0, nHeadLength = 0; if(m_bAlreadyGetHeader == FALSE)
{
//去掉包头,达到包体
do
{
ret = Receive(szReadBuf, MAX_RECV_BUFFER);
nHeadLength = GetHeadLength(szReadBuf);
}while(ret <= nHeadLength);
if(ret > nHeadLength)
{
file.Write(szReadBuf + nHeadLength, ret - nHeadLength);
}
m_bAlreadyGetHeader = TRUE; //由于是异步调用OnReceive,所以后面就不用再去掉包头了
} while(TRUE)
{
ZeroMemory(szReadBuf,MAX_RECV_BUFFER);
int num = Receive(szReadBuf, MAX_RECV_BUFFER); if(num == 0 || num == SOCKET_ERROR) //下载结束或网络错误
{
if (GetLastError() != WSAEWOULDBLOCK && num == 0)
{
file.Close(); //注,下载文件几十K或几百K,老会进入这个!就在也没有响应了!不知为什么!!!
return; //难道要用定时器再连接发请求?有方法控制一下吗?
}
break;
} file.Write(szReadBuf, num);
} file.Close();
}
}
else
{
ASSERT(FALSE);
}
}贴了很多代码,不好意思,我刚学socket网络编程,哪位指导一下我这个迷途小程序员....,给个用CAsyncSocket编http下载的程序也行的(是支持断点的就更好了)
解决方案 »
- 关于VS2010中Visual Assist X的使用问题
- teechart 的x轴怎么设置
- ADO 中我删除的是表单中的第一项,为什么删除的是最后一项 急急急急!!!!
- 我想做个像2000里“超级终端”的程序,各位有没有什么思路??谢谢!
- ----->help<------在线等待!!!!!!!!!!!
- 这样的exe如何做?(internet编程相关)
- 如何在登录前实现屏保级程序运行---操作系统暂限于win98
- 世纪初大比惨!!!
- 在主线程中栈中的对象,在子线程中需要访问该对象,当主线程退出注销栈时,子线程还需要使用该内存吗,而报错
- 我想在做一个程序,可以察看或修改其他进程的数据,但。。。
- HTTP_QUERY_LAST_MODIFIED 这个标志需要含哪个头文件?
- 100分,在线等待!如何修改一组中的RadioBox(单选按钮)的默认值?
http://www.yangning.com/pages/chuansheng1.1.htm
继续请教:如果发起第二个连接,那在CHttpAsyncSocket::OnReceive里调用Receive接收到的数据是第一个连接导致的还是第二个连接导致的?如何判断呢?或者发第二连接的时候第一个连接就自动Stop了?
"GET http://expert.csdn.net/XXX.zip HTTP/1.1\r\n"
"Host: n1.n2.n3.n4:port\r\n"
"Accept: */*\r\n"
"Pragma: no-cache\r\n"
"Cache-Control: no-cache\r\n"
"Connection: close\r\n"
"Range: bytes=%nBegin-%nEnd\r\n"
"\r\n",
他要求得到文件从nBegin开始的数据,但第一个请求(我用的方法是跟上面差不多的请求包)也可能会再触发OnReceive响应啊,有什么方法可以区分呢?估计第一条请求可以不用GET,而用其他的请求动作如HEAD来得到(这是HTTP协议本身的问题了)
另外,OnRecvive接收到的数据(相应上面的第二条请求导致的),接收了一部分,一般是几十 到 几百 K就会停止,即文件还没下载完就再也不会有后续OnReceive的动作,而我用CSocket(阻塞)的话都可以下载完全,不知是否有重联的必要或者我的处理还缺少什么设置?