linux socket模拟HTTP请求上传数据

12 篇文章 0 订阅
3 篇文章 0 订阅

    这是用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



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值