这是用socket模拟HTTP请求上传文件的的C++代码,里面有一些从网上摘录的代码,我在这里按我的需求整理后,再次分享出来,一是算作个人笔记,二是为广大看官遇到类似的问题作参考!
#include <string.h> #include <stdlib.h> #include <algorithm> #include <fstream> #include <iostream> using namespace std; #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #define SEND_RQ(MSG) send(sock,MSG,strlen(MSG),0); #define _DEBUG_PRINT(X) X int FindContentLength(string header); int RecvHttpHeader(int socket, string& header); int RecvHttpBody(int socket, string& body, int contentLength); int request(char* hostname, int port, char* url) { struct sockaddr_in sin; int sock = socket (AF_INET, SOCK_STREAM, 0); if (sock == -1) { _DEBUG_PRINT(cout<<"create socket error!"<<endl); return -100; } sin.sin_family = AF_INET; sin.sin_port = htons( (unsigned short)port); //sin.sin_addr.s_addr = inet_addr(hostname); inet_pton(AF_INET, hostname, (void*)&sin.sin_addr); _DEBUG_PRINT( cout<<"Port :"<<sin.sin_port<<", Address : "<< sin.sin_addr.s_addr<<endl); int result = connect (sock,(const struct sockaddr *)&sin, sizeof(sockaddr_in) ); if(result != 0) { _DEBUG_PRINT(cout<<"connect failed"<<endl); return -101; } SEND_RQ("POST "); SEND_RQ(url); SEND_RQ(" HTTP/1.1\r\n"); SEND_RQ("Accept: text/html, image/jpeg, application/x-ms-application, */*\r\n"); SEND_RQ("User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:17.0) Gecko/17.0 Firefox/17.0\r\n"); SEND_RQ("Accept-Language: zh-CN,en-US;q=0.5\r\n"); SEND_RQ("Accept-Encoding: gzip, deflate\r\n"); SEND_RQ("Host: "); SEND_RQ(hostname); SEND_RQ("\r\n"); char *boundary = (char *)"---------------------------41184676334"; char content_type[512]; memset(content_type, 0, 512); strcat(content_type, "Content-Type: multipart/form-data; boundary="); strcat(content_type, boundary); strcat(content_type, "\r\n"); //--Construct request data {filePath, file} char content_before[4096]; memset(content_before, 0, 4096); strcat(content_before, "--"); strcat(content_before, boundary); strcat(content_before, "\r\n"); strcat(content_before, "Content-Disposition: form-data; name=\"filePath\"\r\n\r\n"); strcat(content_before, destPath); strcat(content_before, "\r\n"); strcat(content_before, "--"); strcat(content_before, boundary); strcat(content_before, "\r\n"); strcat(content_before, "Content-Disposition: form-data; name=\"file\"; filename=\""); strcat(content_before, filename); strcat(content_before, "\"\r\n"); strcat(content_before, "Content-Type: application/octet-stream\r\n\r\n"); //strcat(content_before, "Content-Type: image/jpeg\r\n\r\n"); char content_end[1024]; memset(content_end, 0, 1024); strcat(content_end, "\r\n"); strcat(content_end, "--"); strcat(content_end, boundary); strcat(content_end, "--\r\n"); // store the full name of file ifstream fin("/home/abc/test/enjoyor.mp4" ,ios::in|ios::binary); if(!fin){ _DEBUG_PRINT(cout<<"File open error!\n"); close(sock); return -102; } //---get the length of the file int temp = fin.tellg(); fin.seekg(0,ios_base::end); int len = fin.tellg(); fin.seekg(temp); char *lenstr; lenstr = (char*)malloc(128); sprintf(lenstr, "%d", (strlen(content_before)+len+strlen(content_end))); strcat(content_type, "Content-Length: "); strcat(content_type, lenstr); strcat(content_type, "\r\n\r\n"); free(lenstr); SEND_RQ(content_type); _DEBUG_PRINT(cout<<content_type); SEND_RQ(content_before); _DEBUG_PRINT(cout<<content_before); char c[1024]; memset(c, 0,1024); int tmpLen=0; while(!fin.eof()) { if(tmpLen<(len/1024)*1024) { fin.read(c, 1024); send(sock,c,1024,0); sleep(0.001); //milisecond tmpLen+=1024; } else { fin.read(c,len-(len/1024)*1024); send(sock,c,len-(len/1024)*1024,0); break; } } fin.close(); SEND_RQ(content_end); string header; int headerLength = RecvHttpHeader(sock,header); if(headerLength > 0) { if(header.find("200") != string::npos) //HTTP/1.1 200 OK { int contentLength = FindContentLength(header); if(contentLength > 0) { string strBody; RecvHttpBody(sock,strBody,contentLength); _DEBUG_PRINT(cout<<"the sRecvBuf is "<<strBody.c_str()<<endl); } } else //HTTP/1.1 400 or else { _DEBUG_PRINT(cout<<"unexpected http header status!"<<endl); close(sock); return -103; } } else { _DEBUG_PRINT(cout<<"the return string is not http protptype"<<endl); close(sock); return -104; } close(sock); return 0; } int FindContentLength(string header) { transform(header.begin(),header.end(),header.begin(),(int(*)(int)) tolower); string::size_type pos = header.find("content-length",0); if(pos != string::npos) { string::size_type posEnd = header.find("\r\n",pos); string contentString = header.substr(pos,posEnd - pos); _DEBUG_PRINT(cout<<contentString.c_str()); pos = contentString.find(":",0); string strLength = contentString.substr(pos + 1); return (int)std::strtol(strLength.c_str(),NULL,10); } return 0; } //receive header //param: socketId,receivedString int RecvHttpHeader(int socket, string& header) { header.clear(); char chRecvBuf[1]; //endBytes[]{'\r', '\n', '\r', '\n'} char endBytes[] = { 13, 10, 13, 10 }; int posCompare = 0; while(true) { int b = recv(socket,chRecvBuf,1,0); if (b == -1) return -1; header.append(chRecvBuf,1); if(endBytes[posCompare] == chRecvBuf[0]) { posCompare++; if (posCompare == sizeof(endBytes)) { break; } } else { posCompare = 0; } } return header.length(); } //receive http response body int RecvHttpBody(int socket, string& body, int contentLength) { body.clear(); char chRecvBuf[1024]; while (body.length() < contentLength) { memset(chRecvBuf,0,sizeof(chRecvBuf)); int b = recv(socket,chRecvBuf,sizeof(chRecvBuf) - 1,0); if (b == -1) return -1; body.append(chRecvBuf); } return body.length(); }
想了解HTTP上传请求的数据格式,可见我之前的一篇博客http://blog.csdn.net/ronux/article/details/8244840。
参考:http://www.codeguru.com/cpp/i-n/internet/http/article.php/c8813/HTTP-Post-Using-C.htm