web socket RFC6455 connection --asio C++11

#ifndef __APP_WEBSOCKET_CONNECTION_H__
#define __APP_WEBSOCKET_CONNECTION_H__
#include <asio.hpp>
#include "tcp_connection.hpp"

class websocket_connection : public tcp_connection
{
public:
	websocket_connection( const std::tr1::shared_ptr<asio::ip::tcp::socket> & s );
	std::tr1::shared_ptr<asio::ip::tcp::socket> get_socket() ;
	//握手应答后调用该方法
	void start_read();
	~websocket_connection();
	//buf为payload数据,write方法内部自动加上web socket frame的头部.
	void write( const std::tr1::shared_ptr<buffer> & buf);
	//服务器接受到连接时,调用该方法执行握手过程
	void start_handshake();
	//设置接收到消息的回调方法
	void set_message_handler(const OnMessage & on_message);
protected:
	//读取web socket frame 的最小长度值
	void read_min_head();
	//读取剩余的数据、在一个比较大的包中,可能会出现多次调用该方法才读到一个完整的包
	void read_leave_data( int leave_len );
private:
	shared_ptr<buffer> read_buf;
	OnMessage on_message_;

};

#endif

websocket_connection::websocket_connection( const std::tr1::shared_ptr<asio::ip::tcp::socket> & s ):tcp_connection(s){
		read_buf = get_buffer(8192);
		read_buf->size(8192);
		}
	std::tr1::shared_ptr<asio::ip::tcp::socket> websocket_connection:: get_socket() { return socket_;}

	void websocket_connection::  start_read(){
		//从包头读取
		read_min_head();
	}
	websocket_connection::~websocket_connection(){
		LOG(ERROR)<<"~websocket_connection";
	}
	void websocket_connection::write( const std::tr1::shared_ptr<buffer> & buf){

		websocket_frame frame;
		frame.fin = true;
		frame.mask = true;//使用mask、某些浏览器版本较低不能使用
		frame.opcode = 0x02;//发送的是二进制数据
		buf->offset(4);
		frame.payload = buf;
		frame.package_size();
		if( frame.payload_len == 127 ){
			LOG(ERROR)<<"ignore big message.."<<buf->capacity();
			return;
		}
		shared_ptr<buffer> frame_buf = frame.package();

		tcp_connection::write(frame_buf);

	}
void websocket_connection::read_min_head(){
		auto buf = asio::buffer( read_buf->data(),websocket_frame::fix_min_len);

		auto self(shared_from_this());

		auto read_handler = [self,this](std::error_code ec, std::size_t length){
			if( ec ){
				LOG(ERROR)<<"read_min_head error:"<<ec.message();
				if( on_error_ ){
					on_error_(ec.message());
				}
			}else{
				read_buf->size(length);
				websocket_frame frame;
				int leave_len = frame.unpakcage(read_buf);
				//读取需要解析一个frame所需要的剩余数据
				read_leave_data(leave_len);
			}
		};
		//asio 异步读取指定长度的数据,读取成功后回调read_handler方法.
		asio::async_read(*socket_, buf,read_handler);
	}
	void websocket_connection::read_leave_data( int leave_len ){

		if( read_buf->length() + leave_len > read_buf->capacity() ){
			if( on_error_ ){
				on_error_("data to big...");
			}
			return;
		}
		auto buf = asio::buffer( read_buf->data()+read_buf->length(),leave_len);
		auto self( shared_from_this());

		auto read_handler =[self,this](std::error_code ec, std::size_t length){
			if( ec ){
				if( on_error_ ){
					on_error_(ec.message());
				}
			}else{
				read_buf->size(read_buf->length() + length);
				websocket_frame frame;
				int leave_len = frame.unpakcage(read_buf);
				if( leave_len == 0 ){
					//读取到一个完整的freame了...
					if( on_message_ ){
						on_message_(frame.payload);
					}

					read_buf->size(0);
					start_read();
				}else{
					//如果不够、则继续读取剩余的字节.

					read_leave_data(leave_len);
				}
			}
		};
		asio::async_read(*socket_, buf,read_handler);
	}

void websocket_connection::start_handshake(){
	shared_ptr<buffer> buf = get_buffer(512);
	auto  asio_buf = asio::buffer( buf->data(), 512);
	auto self(shared_from_this());

	socket_->async_read_some( asio_buf,
		[self,this,buf]( const asio::error_code& error,  std::size_t bytes_transferred ){
			    if( error ){
					if( on_error_ ){
						on_error_(error.message());
					}
					recycle_buffer(buf);
					return;
			    }
				std::string data((const char*)buf->data(),bytes_transferred);
				recycle_buffer(buf);

				std::string key="Sec-WebSocket-Key:";
				auto pos = data.find(key);
				auto posEnd = data.find("\r\n",pos);
				auto value = data.substr(pos + key.length(),posEnd - (pos + key.length()));
				std::string sha1Src = trim(value);
				sha1Src += std::string("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");

				unsigned char sha1out[20];
				sha1((const unsigned char *)sha1Src.c_str(),sha1Src.length(),sha1out);
				std::vector<unsigned char> data64;
				for( auto c: sha1out) data64.push_back(c);

				std::ostringstream os_rsp;
				os_rsp<<"HTTP/1.1 101 Switching Protocols\r\n"
    				  <<"Upgrade: websocket\r\n"
				      <<"Connection: Upgrade\r\n"
				      <<"Sec-WebSocket-Accept: "<<base64Encode(data64)<<"=\r\n"
					  <<"\r\n";
				std::string rsp = os_rsp.str();

				socket_->async_send(asio::buffer(rsp),[self,this](const asio::error_code& ec, std::size_t bytes_transferred){

				});
				start_read();//握手应答后,启动对web socke frame的读
			});
}

void websocket_connection::set_message_handler(const OnMessage & on_message){
	on_message_ = on_message;
}

使用;;

void init_service_admin_websocket( asio::io_service & io){

	static std::once_flag init_flag;
	std::call_once( init_flag,[&io]{
		auto new_connected_handler = []( const std::tr1::shared_ptr<asio::ip::tcp::socket> & s)
		{//新连接到来时的回调方法
			shared_ptr<websocket_connection> websocket( new websocket_connection(s));
			//设置错误发生时的回调方法
			auto on_error =[websocket](const std::string & error ){//主要清理资源
				LOG(ERROR)<<error<<" "<<websocket->name();
				sessions::clear_session(websocket);
				websocket.reset();
			};
			websocket->set_error_handler(on_error);

			std::tr1::weak_ptr<websocket_connection> wpsocket(websocket);
			//设置接收到消息时的回调方法,websocket frame的payload
			auto on_message = [wpsocket]( const std::tr1::shared_ptr<buffer> & buf)
			{
				//消息分发

			};

			websocket->set_message_handler(on_message);

			websocket->start_handshake();//启动握手

		};
		unsigned int port = 80;
	 	tcp_server * srv (new tcp_server(io, port , new_connected_handler));
	 	srv->start_accept();
		});
}

web socket RFC6455 connection --asio C++11,布布扣,bubuko.com

时间: 2024-11-12 18:24:06

web socket RFC6455 connection --asio C++11的相关文章

Web Socket rfc6455 握手 (C++)

std::string data((const char*)buf->data(),bytes_transferred); recycle_buffer(buf); std::string key="Sec-WebSocket-Key:"; auto pos = data.find(key); auto posEnd = data.find("\r\n",pos); auto value = data.substr(pos + key.length(),pos

web socket RFC6455 frame 打包、解包

#ifndef __APP_WEBSOCKET_FRAME_H__ #define __APP_WEBSOCKET_FRAME_H__ #include "memory.hpp" class buffer; struct websocket_frame { websocket_frame(); ~websocket_frame(); static const unsigned int fix_min_len = 2; static const unsigned int fix_mask

ASP.NET Web API上实现 Web Socket

1. 什么是Web Socket Web Socket是Html5中引入的通信机制,它为浏览器与后台服务器之间提供了基于TCP的全双工的通信通道.用以替代以往的LongPooling等comet style的实时解决方案.基于它们之间的比较以及Web Socket的优势参考https://www.websocket.org/quantum.html. 2. Web Socket如何工作 Connect Web Socket在建立之前需要先与后台服务器进行握手.具体来说通过如下Http请求: GE

web socket教程

web socket是一种网络通信协议,很多网页应用中都会使用到它,比如聊天室,选票等等. 一.为什么需要WebSocket? HTTP是无连接(无连接的含义是限制每次连接只处理一个请求.服务器处理完客户的请求,并收到客户的应答后,即断开连接.采用这种方式可以节省传输时间) HTTP是无状态(HTTP协议是无状态协议.无状态是指协议对于事务处理没有记忆能力.缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大.另一方面,在服务器不需要先前信息时它的应答就较

轮询、长轮询与Web Socket的前端实现页面数据实时

Web Socket 应用场景:实现即时通讯:如股票交易行情分析.聊天室.在线游戏等,替代轮询和长轮询 1.轮询 轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP request,然后由服务器返回最新的数据给客户端的浏览器.这种传统的HTTP request 的模式带来很明显的缺点 – 浏览器需要不断的向服务器发出请求,然而HTTP request 的header是非常长的,里面包含的有用数据可能只是一个很小的值,这样会占用很多的带宽. var xhr = new XMLHtt

web socket 心跳包的实现方案

web socket 心跳包的实现方案05/30/2010 现在网络环境错综复杂,socket心跳包是获得健康强壮的连接的有效解决方案,今天,我们就在web socket中实现心跳包方案,是的,尽管我们只是做一个简单的聊天室,但我们让他稳定可靠一些一点也没有错. 我的心跳包方案很是简单,原理就是间隔发送心跳包数据给服务器,服务器在一定时间内发回心跳包响应,对比超时限定,如果超过设定的超时时间,则认为当前与服务器的websocket连接已经断开,关闭当前web socket连接,善后处理,例如重新

Node.js + Web Socket 打造即时聊天程序嗨聊

前端一直是一块充满惊喜的土地,不仅是那些富有创造性的页面,还有那些惊赞的效果及不断推出的新技术.像node.js这样的后端开拓者直接将前端人员的能力扩大到了后端.瞬间就有了一统天下的感觉,来往穿梭于前后端之间代码敲得飞起,从此由前端晋升为'前后端'. 图片来自G+ 本文将使用Node.js加web socket协议打造一个网页即时聊天程序,取名为HiChat,中文翻过来就是'嗨聊',听中文名有点像是专为寂寞单身男女打造的~ 其中将会使用到express和socket.io两个包模块,下面会有介绍

轮询、长轮询与Web Socket的前端实现

Web Socket 应用场景:实现即时通讯:如股票交易行情分析.聊天室.在线游戏等,替代轮询和长轮询 轮询 轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP request,然后由服务器返回最新的数据给客户端的浏览器.这种传统的HTTP request 的模式带来很明显的缺点 – 浏览器需要不断的向服务器发出请求,然而HTTP request 的header是非常长的,里面包含的有用数据可能只是一个很小的值,这样会占用很多的带宽. var xhr = new XMLHttpR

web socket and web worker 基础原理及使用

个人认为HTML5最吸引人的两大功能, web socket 和 worker为构建高效能的web应用提供了新的参考方案. 大体来说,web socket提供更高效的传输协议,web worker提供多线程提高web应用计算效率.最近项目有用到,对应两个问题的解决,目前运行效果来看还是很不错. 这里主要是总结这两个技术的基础原理,和常用API.备忘,也列举关键掌握点,入门和基础使用足以. Web Socket websocket是一种协议,本质上和http,tcp一样.协议是用来说明数据是如何传