cocos2d-x 通过socket实现http下载及断点续传的实现
2013-09-10 22:12
585 查看
代码未经进一步的整理,可能比较混乱。
首先,2dx的socket库由BSSocket组成。可跨平台,在windows上已验证。
及cpp的实现
通过ConnectSyn实现连接,若失败则返回false
其次在其基础上封装了一层HttpSocket通过这一层的封装实现对http连接的下载
主要由静态方法
其中 getRange(string(szValue), downFrom, downTo, fileSize) 解析http头中是否是断点续传的连接信息。
其中断点续传用C++的fstream用普通的ios::out打开会清除文件内容,所以需要用outFile.open(saveFile.c_str(), ios::out|ios::binary);
而其中如果不设置 ios::binary 这种模式的话,在下载的资源文件中如果碰到\r\n 此时进行写入的话,如果用16进制打开就会发现从0D0A变成了0D0D0A,这样导致了下载的文件与实际的文件相差甚远。
在下载过程中应该在一个临时文件里记录下载的信息,以保证下次打开可断点续传。
调用的方式为
比如下载超级兔子链接 http://dd.pctutu.com/soft/srramdisk.exe 则完整下载的话可调用
CHttpSocket::downFile("dd.pctutu.com", "/soft/srramdisk.exe", 80, "F:/srramdisk.exe");
如果想多次断点续传下载的话可以调用如下
CHttpSocket::downFile("dd.pctutu.com", "/soft/srramdisk.exe", 80, "F:/srramdisk.exe", 0, 10);
0表示最开始的字节位置,10表示结束的字节位置
CHttpSocket::downFile("dd.pctutu.com", "/soft/srramdisk.exe", 80, "F:/srramdisk.exe", 11, 0);
11表示最开始的字节位置,0表示不输入,则默认从起始位置到最后一个位置。
完整源码已上传到 http://download.csdn.net/detail/w273732573/6245965,初版代码,如果有什么不对的话请指证。
首先,2dx的socket库由BSSocket组成。可跨平台,在windows上已验证。
#ifndef _NET_BSSOCKET_H_ #define _NET_BSSOCKET_H_ #ifdef WIN32 #include <winsock.h> #include <windows.h> typedef int socklen_t; #else #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <fcntl.h> #include <unistd.h> #include <sys/stat.h> #include <sys/types.h> #include <arpa/inet.h> typedef int SOCKET; //#pragma region define win32 const variable in linux #define INVALID_SOCKET -1 #define SOCKET_ERROR -1 //#pragma endregion #endif #include "pthread/pthread.h" #include <iostream> #include <vector> class BSSocket; using namespace std; static BSSocket* bsSocket = NULL; const int MAX_BSSOCKETMSG_BUFF = 1024 * 64; class BSSocket { private: static unsigned char socketBuff[MAX_BSSOCKETMSG_BUFF]; static unsigned long socketBuffLen; bool need_quit; bool isConnected; char* connectIp; unsigned int connectPort; // Send socket public: int Send(const char* buf, int len, int flags = 0); BSSocket(SOCKET sock = INVALID_SOCKET); static BSSocket* getInstance(); void initConnect(const char* ip, unsigned short port); ~BSSocket(); // Create socket object for snd/recv data bool Create(int af, int type, int protocol = 0); // Connect socket bool Connect(const char* ip, unsigned short port); bool ConnectSyn(const char* ip, unsigned short port); //#region server // Bind socket bool Bind(unsigned short port); // Listen socket bool Listen(int backlog = 5); // Accept socket bool Accept(BSSocket& s, char* fromip = NULL); //#endregion // Recv socket int Recv(char* buf, int len, int flags = 0); // Close socket int Close(); // Get errno int GetError(); //#pragma region just for win32 // Init winsock DLL static int Init(); // Clean winsock DLL static int Clean(); //#pragma endregion BSSocket& operator = (SOCKET s); operator SOCKET (); int m_nRecvBufLen; char m_szRecvBuf[MAX_BSSOCKETMSG_BUFF + 1]; /*接收缓存区*/ int getFd() { return m_sock; }; SOCKET m_sock; }; #endif // !_NET_BSSOCKET_H_
及cpp的实现
#include "BSSocket.h" #ifdef WIN32 #pragma comment(lib, "wsock32") #endif BSSocket::BSSocket(SOCKET sock) :need_quit(false),isConnected(false), connectIp(NULL), connectPort(0) { m_sock = sock; } BSSocket::~BSSocket() { } int BSSocket::Init() { #ifdef WIN32 /* http://msdn.microsoft.com/zh-cn/vstudio/ms741563(en-us,VS.85).aspx typedef struct WSAData { WORD wVersion; //winsock version WORD wHighVersion; //The highest version of the Windows Sockets specification that the Ws2_32.dll can support char szDescription[WSADESCRIPTION_LEN+1]; char szSystemStatus[WSASYSSTATUS_LEN+1]; unsigned short iMaxSockets; unsigned short iMaxUdpDg; char FAR * lpVendorInfo; }WSADATA, *LPWSADATA; */ WSADATA wsaData; //#define MAKEWORD(a,b) ((WORD) (((BYTE) (a)) | ((WORD) ((BYTE) (b))) << 8)) WORD version = MAKEWORD(2, 0); int ret = WSAStartup(version, &wsaData);//win sock start up if ( ret ) { // cerr << "Initilize winsock error !" << endl; return -1; } #endif return 0; } //this is just for windows int BSSocket::Clean() { #ifdef WIN32 return (WSACleanup()); #endif return 0; } BSSocket& BSSocket::operator = (SOCKET s) { m_sock = s; return (*this); } BSSocket::operator SOCKET () { return m_sock; } //create a socket object win/lin is the same // af: bool BSSocket::Create(int af, int type, int protocol) { m_sock = socket(af, type, protocol); std::cout << "the errro info" << GetError(); if ( m_sock == INVALID_SOCKET ) { return false; } return true; } bool BSSocket::Connect(const char* ip, unsigned short port) { struct sockaddr_in svraddr; svraddr.sin_family = AF_INET; svraddr.sin_addr.s_addr = inet_addr(ip); svraddr.sin_port = htons(port); int ret = connect(m_sock, (struct sockaddr*)&svraddr, sizeof(svraddr)); if ( ret == SOCKET_ERROR ) { return false; } std::cout << "you are connected" << std::endl; isConnected = true; return true; } bool BSSocket::Bind(unsigned short port) { struct sockaddr_in svraddr; svraddr.sin_family = AF_INET; svraddr.sin_addr.s_addr = INADDR_ANY; svraddr.sin_port = htons(port); int opt = 1; if ( setsockopt(m_sock, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt)) < 0 ) return false; int ret = bind(m_sock, (struct sockaddr*)&svraddr, sizeof(svraddr)); if ( ret == SOCKET_ERROR ) { return false; } return true; } //for server bool BSSocket::Listen(int backlog) { int ret = listen(m_sock, backlog); if ( ret == SOCKET_ERROR ) { return false; } return true; } bool BSSocket::Accept(BSSocket& s, char* fromip) { struct sockaddr_in cliaddr; socklen_t addrlen = sizeof(cliaddr); SOCKET sock = accept(m_sock, (struct sockaddr*)&cliaddr, &addrlen); if ( sock == SOCKET_ERROR ) { return false; } s = sock; if ( fromip != NULL ) sprintf(fromip, "%s", inet_ntoa(cliaddr.sin_addr)); return true; } int BSSocket::Send(const char* buf, int len, int flags) { int bytes; int count = 0; while ( count < len ) { bytes = send(m_sock, buf + count, len - count, flags); if ( bytes == -1 || bytes == 0 ) { std::cout << "the send errro info" << GetError(); return -1; } count += bytes; } return count; } int BSSocket::Recv(char* buf, int len, int flags) { return (recv(m_sock, buf, len, flags)); } int BSSocket::Close() { #ifdef WIN32 return (closesocket(m_sock)); #else return (close(m_sock)); #endif } int BSSocket::GetError() { #ifdef WIN32 return (WSAGetLastError()); #else return (errno); #endif } void BSSocket::initConnect( const char* ip, unsigned short port ) { connectIp = new char[sizeof(ip)]; strcpy(connectIp, ip); connectPort = port; pthread_t initThread; } BSSocket* BSSocket::getInstance() { if(bsSocket == NULL) { bsSocket = new BSSocket; } return bsSocket; } bool BSSocket::ConnectSyn( const char* ip, unsigned short port ) { Init(); Create(AF_INET, SOCK_STREAM, 0); bool success = Connect(ip, port); std::cout << "connect status is = " << success << std::endl; return success; }
通过ConnectSyn实现连接,若失败则返回false
其次在其基础上封装了一层HttpSocket通过这一层的封装实现对http连接的下载
主要由静态方法
bool CHttpSocket::downFile( string strServer, string strObject, int nPort, string saveFile, int from, int to ) { CHttpSocket httpSocket; long nLength; const char *pRequestHeader = NULL; pRequestHeader = httpSocket.FormatRequestHeader((char *)strServer.c_str(),(char *)strObject.c_str(),nLength, NULL, NULL, from, to); httpSocket.Connect((char *)strServer.c_str(), nPort); httpSocket.SendRequest(); httpSocket.SetTimeout(10000,0); char szValue[100]; httpSocket.GetField("Content-Length",szValue,30); int nFileSize = atoi(szValue); int downFrom = 0, downTo = 0, fileSize; httpSocket.GetField("Content-Range",szValue,100); if(getRange(string(szValue), downFrom, downTo, fileSize)) { int nCompletedSize = 0; int nDownloadSize = downTo - downFrom + 1; ensureFile(saveFile, fileSize); fstream outFile; outFile.open(saveFile.c_str(), ios::out|ios::in|ios::binary); outFile.seekp(downFrom); char pData[8192]; int nReceSize = 0; long dwStartTime,dwEndTime; while(nCompletedSize < nDownloadSize) { dwStartTime = GetTickCount(); nReceSize = httpSocket.Receive(pData,8192); if(nReceSize == 0) { printf("服务器已经关闭连接."); break; } if(nReceSize == -1) { printf("接收数据超时."); break; } dwEndTime = GetTickCount(); outFile.write(pData, nReceSize); nCompletedSize += nReceSize; printf("write count is %d", outFile.gcount()); printf("download size is %d, all size is %d", nCompletedSize, nFileSize); } outFile.close(); } else { int nCompletedSize = 0; fstream outFile; outFile.open(saveFile.c_str(), ios::out|ios::binary); char pData[8192]; int nReceSize = 0; long dwStartTime,dwEndTime; while(nCompletedSize < nFileSize) { dwStartTime = GetTickCount(); nReceSize = httpSocket.Receive(pData,8192); if(nReceSize == 0) { printf("服务器已经关闭连接."); break; } if(nReceSize == -1) { printf("接收数据超时."); break; } dwEndTime = GetTickCount(); outFile.write(pData, nReceSize); nCompletedSize += nReceSize; printf("write count is %d", outFile.gcount()); printf("download size is %d, all size is %d", nCompletedSize, nFileSize); } outFile.close(); } return true; }
其中 getRange(string(szValue), downFrom, downTo, fileSize) 解析http头中是否是断点续传的连接信息。
其中断点续传用C++的fstream用普通的ios::out打开会清除文件内容,所以需要用outFile.open(saveFile.c_str(), ios::out|ios::binary);
而其中如果不设置 ios::binary 这种模式的话,在下载的资源文件中如果碰到\r\n 此时进行写入的话,如果用16进制打开就会发现从0D0A变成了0D0D0A,这样导致了下载的文件与实际的文件相差甚远。
在下载过程中应该在一个临时文件里记录下载的信息,以保证下次打开可断点续传。
调用的方式为
比如下载超级兔子链接 http://dd.pctutu.com/soft/srramdisk.exe 则完整下载的话可调用
CHttpSocket::downFile("dd.pctutu.com", "/soft/srramdisk.exe", 80, "F:/srramdisk.exe");
如果想多次断点续传下载的话可以调用如下
CHttpSocket::downFile("dd.pctutu.com", "/soft/srramdisk.exe", 80, "F:/srramdisk.exe", 0, 10);
0表示最开始的字节位置,10表示结束的字节位置
CHttpSocket::downFile("dd.pctutu.com", "/soft/srramdisk.exe", 80, "F:/srramdisk.exe", 11, 0);
11表示最开始的字节位置,0表示不输入,则默认从起始位置到最后一个位置。
完整源码已上传到 http://download.csdn.net/detail/w273732573/6245965,初版代码,如果有什么不对的话请指证。
相关文章推荐
- cocos2d-x 通过socket实现http下载及断点续传的实现
- 用PHP实现 HTTP断点续传、分块下载文件(Socket)
- .Net/C#: 实现支持断点续传多线程下载的 Http Web 客户端工具类
- delphi IdHTTP实现Get方法下载文件,断点续传
- Linux下使用Socket实现http文件下载
- .Net/C#: 实现支持断点续传多线程下载的 Http Web 客户端工具类 (第2版) (C# DIY HttpWebClient)
- .Net/C#: 实现支持断点续传多线程下载的 Http Web 客户端工具类 (C# DIY HttpWebClient)
- Java基于Socket实现HTTP下载客户端
- Android平台下通过HTTP协议实现断点续传下载
- 反射机制及开源框架xUitls的使用,使用HttpUtils通过断点续传下载文件
- Net/C#: 实现支持断点续传多线程下载的 Http Web 客户端工具类 (C# DIY HttpWebClient)
- 通过WINET实现的http断点下载
- ftp和http断点续传及下载delphi实现
- Android通过HTTP协议实现断点续传下载
- 实现支持断点续传多线程下载的 Http Web 客户端工具类()
- Android学习笔记:通过Android之Service实现文件断点续传下载
- ftp和http断点续传及下载的Delphi实现
- Windows Winnet 实现HTTP 文件断点续传下载
- ftp和http断点续传及下载delphi实现
- 直接用socket实现HTTP下载