代码未经进一步的整理,可能比较混乱。
首先,2dx的socket库由BSSocket组成。可跨平台,在windows上已验证。
1 #ifndef _NET_BSSOCKET_H_ 2 #define _NET_BSSOCKET_H_ 3 4 #ifdef WIN32 5 #include6 #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表示不输入,则默认从起始位置到最后一个位置。
完整源码已上传到 ,初版代码,如果有什么不对的话请指证。