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. 一款非常棒的纯CSS3 3D菜单演示及制作教程

    原文:一款非常棒的纯CSS3 3D菜单演示及制作教程 这段时间比较忙,很久没在这里分享一些漂亮的HTML5和CSS3资源了,今天起的早,看到一款很不错的CSS3 3D菜单,觉得非常上眼,就将它分享给大 ...

  2. cocos2d-x 移植android竖,横屏设置

    AndroidManifest.xml于android:screenOrientation现场控制屏幕方向,默认为横屏 android:screenOrientation="landscap ...

  3. linux 虚拟文件系统

    转自:https://www.ibm.com/developerworks/cn/linux/l-cn-vfs/ Linux 允许众多不同的文件系统共存,并支持跨文件系统的文件操作,这是因为有虚拟文件 ...

  4. 深入理解C指针之六:指针和结构体

    原文:深入理解C指针之六:指针和结构体 C的结构体可以用来表示数据结构的元素,比如链表的节点,指针是把这些元素连接到一起的纽带. 结构体增强了数组等集合的实用性,每个结构体可以包含多个字段.如果不用结 ...

  5. AngularJS之使用服务封装

    AngularJS之使用服务封装可复用代码   创建服务组件 在AngularJS中创建一个服务组件很简单,只需要定义一个具有$get方法的构造函数, 然后使用模块的provider方法进行登记: / ...

  6. 《Windows游戏编程技巧大师》就DirectDraw而创建DirectDraw知识笔记

    1.DirectDraw 这可能是Directx中最重要的技术,由于它是2D图形赖以实现的渠道.也是Direct3D构建于其上的帧缓冲层. 2.DirectDraw是由非常多借口组成的.共同拥有5个接 ...

  7. Swift入门教程:基本语法(二)

    数字格式 数字可以增加额外的格式,使它们更容易阅读 可以增加额外的零 0 let money = 001999           // 1999 let money2 = 001999.000   ...

  8. APlayer组件自制播放器

    .NET中使用APlayer组件自制播放器 2015-02-02 09:46 by xiaozhi_5638, 402 阅读, 9 评论, 收藏, 编辑 目录 说明 APlayer介绍 APlayer ...

  9. checkbox 选择功能和反选

    使用jQuery实现checkbox全补选和反选功能.什么时候checkbox选择禁用时,不涉及功能 <!DOCTYPE html> <html> <head> & ...

  10. PHP 1:在Windows上安装和配置PHP,Apache和My SQL

    原文:PHP 1:在Windows上安装和配置PHP,Apache和My SQL 如果你Google一把类似的主题,你会发现相关的文章可以塞满你的硬盘.在这里之所以把它再次拿出来,目的是想记录我作为一 ...