ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

简洁的c++http协议获取内容(一)

2021-02-17 17:30:43  阅读:364  来源: 互联网

标签:简洁 http get c++ char timeout rc sockfd


使用http协议的好处

1、http协议简单,成熟
2、短链接获取数据后释放
不过在c++中,如果时简单的get 、 post 交互,c++ 不像java,node,或者go那样,随手就写出来,不理解网络包或者没有经验,无非就只能引入包,引入一个包并不难,本来很轻量的程序为了一个两个简单的交互引入越来越多的包并不是好事情,下面我们徒手写一段,可以使用该代码简单地获取数据而不用引入其他包。

http协议 get

int getData(const char* host, unsigned short port, const char* path, const char* get_content)
	{
		//GET请求方式
		std::stringstream stream;
		if(get_content!=NULL && strlen(get_content) > 0)
		//if (strlen(get_content) > 0)
			stream << "GET " << path << "?" << get_content;
		else
			stream << "GET " << path;
		stream << " HTTP/1.0\r\n";
		stream << "Host: " << host << "\r\n";
		stream << "User-Agent: cool duck /1.1.1\r\n";
		stream << "Connection:close\r\n\r\n";
		//string temp = stream.str();
		//cout << "len is " << temp.size() << endl;
		return Http(host, port, stream.str().c_str());
	}

这段程序使用标准的get 来向服务器获取请求内容,下面show me the code,直接使用socket和缓存获取内容。

int Http(const char* host, unsigned short port, const char *request)
	{
		SOCKET sockfd;
		struct sockaddr_in address;
		struct hostent *server;

		sockfd = socket(AF_INET, SOCK_STREAM, 0);
		address.sin_family = AF_INET;
		address.sin_port = htons(port);
		//getaddrinfo()
		server = gethostbyname(host);
		memcpy((char *)&address.sin_addr.s_addr, (char*)server->h_addr, server->h_length);

#ifdef _WIN32
		int ret = 0;
		//int timeout = 2000; //2s
		//这样做在Linux环境下是不会产生效果的,须如下定义:
		struct timeval timeout = { 2,0 };
		//设置发送超时
		setsockopt(sockfd,SOL_SOCKET,SO_SNDTIMEO,(char *)&timeout, sizeof(struct timeval));
		//设置接收超时
		setsockopt(sockfd,SOL_SOCKET,SO_RCVTIMEO,(char *)&timeout, sizeof(struct timeval));
			

//		ret = setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (const char*)&timeout, sizeof(timeout));
//		ret = setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout));
#endif
		if (-1 == connect(sockfd, (struct sockaddr *)&address, sizeof(address))) {
#ifdef _WIN32 
			closesocket(sockfd);
#endif
			cout << "connection error!" << std::endl;
			return -1;
		}



#ifdef WIN32
		int iRes = send(sockfd, request, (int)strlen(request), 0);
		if (iRes == SOCKET_ERROR) {
			printf("send failed: %d\n", WSAGetLastError());
			closesocket(sockfd);
			return -1;
		}
#else
		struct timeval timeout = { 2,0 };//2s
		int ret = setsockopt(sock_fd, SOL_SOCKET, SO_SNDTIMEO, (const char*)&timeout, sizeof(timeout));
		int ret = setsockopt(sock_fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout));
		write(sockfd, request, strlen(request));
#endif
		_data.clear();
#define BUF_SIZE 128
		char buf[128+1];
		int offset = 0;
		int rc;

		do {
			int buflen = BUF_SIZE - offset;
			if (buflen == 0)
			{
				printf("not enough mem,so continue\n");
				offset = 0;
				buflen = BUF_SIZE;
				//break;
			}
#ifdef WIN32
			rc = recv(sockfd, buf + offset, buflen, 0);
			//rc = recv(sockfd, buf + offset, buflen, MSG_WAITALL);
#else
			rc = read(sockfd, buf + offset, 1024);
#endif
			if (rc > 0) {
				offset += rc;
				buf[rc] = '\0';
				_data += buf;
				printf("Bytes received: %d\n", rc);
			}
			else if (rc == 0)
			{

				printf("Connection closed\n");
			}
			else
				printf("recv failed: %d\n",rc);
		} while (rc > 0);

#ifdef WIN32
		closesocket(sockfd);
#else
		close(sockfd);
#endif
		cout << _data << endl;


	}

要点

函数里面定义缓存大小是关键,因为并不知道数据量到底有多大,所以定义为128字节
#define BUF_SIZE 128,写一个nodejs server 来直接返回数据,nodejs代码附在下方
实际上,http协议返回的头部一般都不止128字节,我们使用的量肯定是小的,可以自行修改BUF_SIZE,变大,比如256,甚至更大,在嵌入式系统中,显然字节数目不用过大。
其他:
1、使用循环缓冲来接收字节是比较好的方式,为了方便,直接使用stl的string 来存储接收的值。
2、没有解析所有http头部,实际上结束后可以使用string的find函数来查找字节偏移,得到内容字节数后再获取实际内容
3、如果是用来接收文件,这一段代码要简略修改,首先接收缓冲值要变大,其次不能使用stl string 的相加,可以解析完头部后直接存储写到外部存储中。

结果

调用函数,封装程http_content


int main()
{
	http_connect conn;
	conn.getData("127.0.0.1", 8000, "/", NULL);
	conn.getData("127.0.0.1", 8000, "/test", NULL);
	getchar();
	//std::cout << "Hello World!\n";
}

以下为执行结果
http协议获取内容
图上可以看出,128字节缓存是不够的,分多次获取了数据,第一次get获取数据的时候拿到128字节数据,第二次的时候拿到78字节,流程收到服务器的close信号,直接退出,string 中保存了所有数据,但是需要解析,才能拿到{ret:ok},这个数据

总结

至此已经可以拿到get的数据,虽然简单,但是有效,不用引入额外的库。将在第二篇中讲解解析http头部和获取内容,以及post数据,在往后可以直接解析简单的json数据,而不引入库。

nodejs 服务器

这个就简单了,为了测试而已

var express = require('express');
var app = express();
var http = require('http').Server(app);
var httpget = require('http');
var bodyParser = require('body-parser');
var session = require('express-session');

//在线
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json());

app.use(session({
    secret: 'secret',
    resave: true,// don't save session if unmodified
    saveUninitialized: false,// don't create session until something stored
    cookie: {
        maxAge: 1000 * 60 * 10 //过期时间设置(单位毫秒)
    }
}));
app.use(express.static(__dirname));
app.get("/",function(req,res){
     res.send("{ret:ok}");
 });
app.get("/test",function(req,res){
     res.send("{ret:test}");
});
app.post("/test",function(req,res){
     res.send("{ret:test}");
 });
http.listen(8000, function () {
    console.log('listening on *:8000');
});

标签:简洁,http,get,c++,char,timeout,rc,sockfd
来源: https://blog.csdn.net/qianbo042311/article/details/113835551

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有