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 这种模式的话,在下载的资源文件中如果碰到\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下载及断点续传的实现的更多相关文章

  1. Android开发之多线程下载、断点续传、进度条和文本显示

    代码实现了在Android环境下的多线程下载.断点续传.进度条显示和文本显示百分数: import java.io.BufferedReader; import java.io.File; impor ...

  2. Java开发之多线程下载和断点续传

    代码实现了多线程下载和断点续传功能 import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream ...

  3. java多线程下载和断点续传

    java多线程下载和断点续传,示例代码只实现了多线程,断点只做了介绍.但是实际测试结果不是很理想,不知道是哪里出了问题.所以贴上来请高手修正. [Java]代码 import java.io.File ...

  4. ios 后台下载,断点续传总结

    2018年12月05日 16:09:00 weixin_34101784 阅读数:5 https://blog.csdn.net/weixin_34101784/article/details/875 ...

  5. Azure存储上传下载(断点续传)

    最近有一个客户需要将文件系统(VM搭建)迁移到Azure存储上,对于Azure存储这里就不多做介绍,但是该客户由于网络原因下载文件的时候经常出现上传中断,所以想在Azure 存储上实现下载的断点续传. ...

  6. AFNetworking 下载文件断点续传操作

    一:本示例代码包括: 文件下载,写入指定目录 下载进度,回调Progress; 断点续传,下载暂停,继续操作: 二:本项目 适用于 AFNetworking 1.x 版本 #pragma mark 断 ...

  7. python网络编程-socket上传下载文件(包括md5验证,大数据发送,粘包处理)

    ftp server 1) 读取文件名 2)检查文件是否存在 3)打开文件 4)检查文件大小 5)发送文件大小给客户端 6)等客户端确认 7)开始边读边(md5计算)发数据 8)给客户端发md5 ft ...

  8. python实现socket上传下载文件-进度条显示

    在python的socket编程中,可以实现上传下载文件,并且在下载的时候,显示进度条,具体的流程如下图所示: 1. 服务器端代码如下: [root@python 519]# cat server.p ...

  9. 【FTP】FTP文件上传下载-支持断点续传

    Jar包:apache的commons-net包: 支持断点续传 支持进度监控(有时出不来,搞不清原因) 相关知识点 编码格式: UTF-8等; 文件类型: 包括[BINARY_FILE_TYPE(常 ...

随机推荐

  1. String不变性

    String不变性理解类型: String x = "java"; System.out.println(x);//输出为java x.concat("java" ...

  2. C和指针 (pointers on C)——第一章:高速启动

    大多数人并不认为有几类人猿学校计划非常赞同C学习好,然后看多本书. 仅仅作为读书笔记写.有时还包括一些题目和答案. 这样的公开栏,这两种玉引砖敲,对于自勉,鼓励王! 第一章:手 我每次都是复习的来写. ...

  3. C---通过指针访问数组

    C语言规定:如果指针变量P已指向数组中的一个元素,则P+1指向同一数组中的下一个元素. 引入指针变量后,就可以用俩种方法来访问数组元素了. 如果p的初值为&a[0],则: P+i 和a+i 就 ...

  4. MVC验证07-自定义Model级别验证

    原文:MVC验证07-自定义Model级别验证 在一般的自定义验证特性中,我们通过继承ValidationAttribute,实现IClientValidatable,只能完成对某个属性的自定义验证. ...

  5. HDU 4324 Triangle LOVE 拓扑排序

    Problem Description Recently, scientists find that there is love between any of two people. For exam ...

  6. Java多线程详解

    Java线程:概念与原理 一.操作系统中线程和进程的概念 现在的操作系统是多任务操作系统.多线程是实现多任务的一种方式. 进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程 ...

  7. Hibernat之关系的处理一对一处理

    第一步:编写两个pojo,比如一个学生表一个班级表  这里使用注解. 需要 公司表: package com.qcf.pox; import javax.persistence.CascadeType ...

  8. How to: Installshield做安装包时如何添加文件

    原文:How to: Installshield做安装包时如何添加文件 我一直以为这不是一个问题,可是没想到在几个群内,对于如何向安装包添加文件不解的大有人在,今日稍暇,整理成篇,以供参考 首先我想再 ...

  9. Windows7下搭建Django运行环境

    一直都是在Linux环境下搭建django的运行环境,开学因为需要叫前端的同学帮忙修改模板,所以需要在Windows下搭建起运行环境,想来PHP倒是有不少集成开发环境,Python倒是少的可怜…只在w ...

  10. 数据库备份还原工具EMS SQL Angel for SQL Server发布1.3版本

    EMS公司,是专门从事企业数据库以及内置于多层次客户服务器结构自动化开发.其EMS SQL Angel for SQL Server工具,便是SQL Servers数据库数据备份还原工具,并且还能使用 ...