博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
cocos2d-x 通过socket实现http下载及断点续传的实现
阅读量:5732 次
发布时间:2019-06-18

本文共 11119 字,大约阅读时间需要 37 分钟。

代码未经进一步的整理,可能比较混乱。

首先,2dx的socket库由BSSocket组成。可跨平台,在windows上已验证。

1 #ifndef _NET_BSSOCKET_H_  2 #define _NET_BSSOCKET_H_  3   4 #ifdef WIN32  5 #include 
6 #include
7 typedef int socklen_t; 8 #else 9 #include
10 #include
11 #include
12 #include
13 #include
14 #include
15 #include
16 #include
17 typedef int SOCKET; 18 19 //#pragma region define win32 const variable in linux 20 #define INVALID_SOCKET -1 21 #define SOCKET_ERROR -1 22 //#pragma endregion 23 #endif 24 25 #include "pthread/pthread.h" 26 #include
27 #include
28 29 class BSSocket; 30 using namespace std; 31 32 static BSSocket* bsSocket = NULL; 33 34 const int MAX_BSSOCKETMSG_BUFF = 1024 * 64; 35 class BSSocket { 36 37 private: 38 39 static unsigned char socketBuff[MAX_BSSOCKETMSG_BUFF]; 40 static unsigned long socketBuffLen; 41 42 bool need_quit; 43 bool isConnected; 44 45 char* connectIp; 46 unsigned int connectPort; 47 // Send socket 48 49 public: 50 int Send(const char* buf, int len, int flags = 0); 51 BSSocket(SOCKET sock = INVALID_SOCKET); 52 static BSSocket* getInstance(); 53 void initConnect(const char* ip, unsigned short port); 54 55 ~BSSocket(); 56 57 // Create socket object for snd/recv data 58 bool Create(int af, int type, int protocol = 0); 59 60 // Connect socket 61 bool Connect(const char* ip, unsigned short port); 62 bool ConnectSyn(const char* ip, unsigned short port); 63 //#region server 64 // Bind socket 65 bool Bind(unsigned short port); 66 67 // Listen socket 68 bool Listen(int backlog = 5); 69 70 // Accept socket 71 bool Accept(BSSocket& s, char* fromip = NULL); 72 //#endregion 73 74 // Recv socket 75 int Recv(char* buf, int len, int flags = 0); 76 77 // Close socket 78 int Close(); 79 80 // Get errno 81 int GetError(); 82 83 //#pragma region just for win32 84 // Init winsock DLL 85 static int Init(); 86 // Clean winsock DLL 87 static int Clean(); 88 //#pragma endregion 89 90 91 92 BSSocket& operator = (SOCKET s); 93 94 operator SOCKET (); 95 96 int m_nRecvBufLen; 97 char m_szRecvBuf[MAX_BSSOCKETMSG_BUFF + 1]; /*接收缓存区*/ 98 99 int getFd() { return m_sock; };100 SOCKET m_sock;101 102 103 };104 105 #endif // !_NET_BSSOCKET_H_

及cpp的实现

1 #include "BSSocket.h"  2   3 #ifdef WIN32  4     #pragma comment(lib, "wsock32")  5 #endif  6   7   8 BSSocket::BSSocket(SOCKET sock)  9     :need_quit(false),isConnected(false), connectIp(NULL), connectPort(0) 10 { 11     m_sock = sock; 12 } 13  14 BSSocket::~BSSocket() 15 { 16 } 17  18 int BSSocket::Init() 19 { 20 #ifdef WIN32 21     /* 22     http://msdn.microsoft.com/zh-cn/vstudio/ms741563(en-us,VS.85).aspx 23  24     typedef struct WSAData {  25         WORD wVersion;                                //winsock version 26         WORD wHighVersion;                            //The highest version of the Windows Sockets specification that the Ws2_32.dll can support 27         char szDescription[WSADESCRIPTION_LEN+1];  28         char szSystemStatus[WSASYSSTATUS_LEN+1];  29         unsigned short iMaxSockets;  30         unsigned short iMaxUdpDg;  31         char FAR * lpVendorInfo;  32     }WSADATA, *LPWSADATA;  33     */ 34     WSADATA wsaData; 35     //#define MAKEWORD(a,b) ((WORD) (((BYTE) (a)) | ((WORD) ((BYTE) (b))) << 8))  36     WORD version = MAKEWORD(2, 0); 37     int ret = WSAStartup(version, &wsaData);//win sock start up 38     if ( ret ) { 39 //        cerr << "Initilize winsock error !" << endl; 40         return -1; 41     } 42 #endif 43      44     return 0; 45 } 46 //this is just for windows 47 int BSSocket::Clean() 48 { 49 #ifdef WIN32 50         return (WSACleanup()); 51 #endif 52         return 0; 53 } 54  55 BSSocket& BSSocket::operator = (SOCKET s) 56 { 57     m_sock = s; 58     return (*this); 59 } 60  61 BSSocket::operator SOCKET () 62 { 63     return m_sock; 64 } 65 //create a socket object win/lin is the same 66 // af: 67 bool BSSocket::Create(int af, int type, int protocol) 68 { 69     m_sock = socket(af, type, protocol); 70     std::cout << "the errro info" << GetError(); 71     if ( m_sock == INVALID_SOCKET ) { 72         return false; 73     } 74     return true; 75 } 76  77 bool BSSocket::Connect(const char* ip, unsigned short port) 78 { 79     struct sockaddr_in svraddr; 80     svraddr.sin_family = AF_INET; 81     svraddr.sin_addr.s_addr = inet_addr(ip); 82     svraddr.sin_port = htons(port); 83     int ret = connect(m_sock, (struct sockaddr*)&svraddr, sizeof(svraddr)); 84     if ( ret == SOCKET_ERROR ) { 85         return false; 86     } 87     std::cout << "you are connected" << std::endl;     88     isConnected = true; 89     return true; 90 } 91  92 bool BSSocket::Bind(unsigned short port) 93 { 94     struct sockaddr_in svraddr; 95     svraddr.sin_family = AF_INET; 96     svraddr.sin_addr.s_addr = INADDR_ANY; 97     svraddr.sin_port = htons(port); 98  99     int opt =  1;100     if ( setsockopt(m_sock, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt)) < 0 ) 101         return false;102 103     int ret = bind(m_sock, (struct sockaddr*)&svraddr, sizeof(svraddr));104     if ( ret == SOCKET_ERROR ) {105         return false;106     }107     return true;108 }109 //for server110 bool BSSocket::Listen(int backlog)111 {112     int ret = listen(m_sock, backlog);113     if ( ret == SOCKET_ERROR ) {114         return false;115     }116     return true;117 }118 119 bool BSSocket::Accept(BSSocket& s, char* fromip)120 {121     struct sockaddr_in cliaddr;122     socklen_t addrlen = sizeof(cliaddr);123     SOCKET sock = accept(m_sock, (struct sockaddr*)&cliaddr, &addrlen);124     if ( sock == SOCKET_ERROR ) {125         return false;126     }127 128     s = sock;129     if ( fromip != NULL )130         sprintf(fromip, "%s", inet_ntoa(cliaddr.sin_addr));131 132     return true;133 }134 135 int BSSocket::Send(const char* buf, int len, int flags)136 {137     int bytes;138     int count = 0;139 140     while ( count < len ) {141         bytes = send(m_sock, buf + count, len - count, flags);142         if ( bytes == -1 || bytes == 0 ) {143             std::cout << "the send errro info" << GetError();144             return -1;145         }146         count += bytes;147     } 148 149     return count;150 }151 152 int BSSocket::Recv(char* buf, int len, int flags)153 {154     return (recv(m_sock, buf, len, flags));155 }156 157 int BSSocket::Close()158 {159 #ifdef WIN32160     return (closesocket(m_sock));161 #else162     return (close(m_sock));163 #endif164 }165 166 int BSSocket::GetError()167 {168 #ifdef WIN32169     return (WSAGetLastError());170 #else171     return (errno);172 #endif173 }174 175 176 177 void BSSocket::initConnect( const char* ip, unsigned short port )178 {179      connectIp = new char[sizeof(ip)];180      strcpy(connectIp, ip);181      connectPort = port;182      pthread_t initThread;183 }184 185 186 187 BSSocket* BSSocket::getInstance()188 {189     if(bsSocket == NULL) {190         bsSocket = new BSSocket;191     }192     return bsSocket;193 }194 195 196 197 bool BSSocket::ConnectSyn( const char* ip, unsigned short port )198 {199     Init();200     Create(AF_INET, SOCK_STREAM, 0);201     bool success = Connect(ip, port);202     std::cout << "connect status is = " << success << std::endl;203     return success;204 }

通过ConnectSyn实现连接,若失败则返回false

 

其次在其基础上封装了一层HttpSocket通过这一层的封装实现对http连接的下载

主要由静态方法

1 bool CHttpSocket::downFile( string strServer, string strObject, int nPort, string saveFile, int from, int to ) 2 { 3     CHttpSocket httpSocket; 4     long nLength; 5     const char *pRequestHeader = NULL; 6     pRequestHeader = httpSocket.FormatRequestHeader((char *)strServer.c_str(),(char *)strObject.c_str(),nLength, NULL, NULL, from, to);     7     httpSocket.Connect((char *)strServer.c_str(), nPort); 8     httpSocket.SendRequest(); 9     httpSocket.SetTimeout(10000,0);10     char szValue[100];11     httpSocket.GetField("Content-Length",szValue,30);12     int nFileSize = atoi(szValue);13 14 15     int downFrom = 0, downTo = 0, fileSize;16     httpSocket.GetField("Content-Range",szValue,100);17     if(getRange(string(szValue), downFrom, downTo, fileSize)) {18         int nCompletedSize = 0;19         int nDownloadSize = downTo - downFrom + 1;20         ensureFile(saveFile, fileSize);21         fstream outFile;22         outFile.open(saveFile.c_str(), ios::out|ios::in|ios::binary);23         outFile.seekp(downFrom);24         char pData[8192];25         int nReceSize = 0;26         long dwStartTime,dwEndTime;27         while(nCompletedSize < nDownloadSize)28         {29             dwStartTime = GetTickCount();30             nReceSize = httpSocket.Receive(pData,8192);31             if(nReceSize == 0)32             {33                 printf("服务器已经关闭连接.");34                 break;35             }36             if(nReceSize == -1)37             {38                 printf("接收数据超时.");39                 break;40             }41             dwEndTime = GetTickCount();42             outFile.write(pData, nReceSize);43             nCompletedSize += nReceSize;44             printf("write count is %d", outFile.gcount());45             printf("download size is %d, all size is %d", nCompletedSize, nFileSize);46         }47         outFile.close();48     } else {49         int nCompletedSize = 0;50         fstream outFile;51         outFile.open(saveFile.c_str(), ios::out|ios::binary);52 53         char pData[8192];54         int nReceSize = 0;55         long dwStartTime,dwEndTime;56         while(nCompletedSize < nFileSize)57         {58             dwStartTime = GetTickCount();59             nReceSize = httpSocket.Receive(pData,8192);60             if(nReceSize == 0)61             {62                 printf("服务器已经关闭连接.");63                 break;64             }65             if(nReceSize == -1)66             {67                 printf("接收数据超时.");68                 break;69             }70             dwEndTime = GetTickCount();71             outFile.write(pData, nReceSize);72             nCompletedSize += nReceSize;73             printf("write count is %d", outFile.gcount());74             printf("download size is %d, all size is %d", nCompletedSize, nFileSize);75         }76         outFile.close();77     }78 79     return true;80 }

其中 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表示不输入,则默认从起始位置到最后一个位置。

完整源码已上传到 ,初版代码,如果有什么不对的话请指证。

 

转载于:https://www.cnblogs.com/tickdream/p/3313554.html

你可能感兴趣的文章
计组_定点数一位乘_布斯公式
查看>>
linux下使用过的命令总结(未整理完)
查看>>
ES6的一些文章
查看>>
LeetCode 198, 213 House Robber
查看>>
New Year Permutation(Floyd+并查集)
查看>>
Qt编写输入法V2018超级终结版
查看>>
<context:component-scan>详解
查看>>
DS博客作业07--查找
查看>>
[JOI2017] サッカー (Soccer)
查看>>
Git 方法
查看>>
[Python] numpy.nonzero
查看>>
2016-11-29
查看>>
C#反射的坑
查看>>
css3 box-shadow阴影(外阴影与外发光)讲解
查看>>
时间助理 时之助
查看>>
nginx快速安装
查看>>
自定义转场动画
查看>>
英国征召前黑客组建“网络兵团”
查看>>
Silverlight 2.5D RPG游戏“.NET技术”技巧与特效处理:(十二)魔法系统
查看>>
[NPM] Run npm scripts in series
查看>>