zoukankan      html  css  js  c++  java
  • cocos2d-x 通过socket实现http下载及断点续传的实现

    cocos2d-x 通过socket实现http下载及断点续传的实现

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

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

    复制代码
      1 #ifndef _NET_BSSOCKET_H_
      2 #define _NET_BSSOCKET_H_
      3 
      4 #ifdef WIN32
      5 #include <winsock.h>
      6 #include <windows.h>
      7 typedef int                socklen_t;
      8 #else
      9 #include <sys/socket.h>
     10 #include <netinet/in.h>
     11 #include <netdb.h>
     12 #include <fcntl.h>
     13 #include <unistd.h>
     14 #include <sys/stat.h>
     15 #include <sys/types.h>
     16 #include <arpa/inet.h>
     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 <iostream>
     27 #include <vector>
     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 server
    110 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 WIN32
    160     return (closesocket(m_sock));
    161 #else
    162     return (close(m_sock));
    163 #endif
    164 }
    165 
    166 int BSSocket::GetError()
    167 {
    168 #ifdef WIN32
    169     return (WSAGetLastError());
    170 #else
    171     return (errno);
    172 #endif
    173 }
    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 这种模式的话,在下载的资源文件中如果碰到 此时进行写入的话,如果用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,初版代码,如果有什么不对的话请指证。

  • 相关阅读:
    Python多线程爬虫爬取电影天堂资源
    BGP协议初探
    dubbo序列化hibernate.LazyInitializationException could not initialize proxy
    Spring Boot打包war jar 部署tomcat
    HSSFClientAnchor 参数说明
    attempt to create delete event with null entity
    解决BUG:CS1617: 选项“6”对 /langversion 无效;必须是 ISO-1、ISO-2、3、4、5 或 Default
    Android Studio :enable vt-x in your bios security,已经打开还是报错的解决方法
    visual studio 2015 开发android
    ASP.NET用QQ,网易发送邮件以及添加附件
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3313621.html
Copyright © 2011-2022 走看看