使用websocketpp进行websocket通信
websocketpp介绍
websocketpp是一个只有头文件的支持websocket协议的C++开源库,支持websocket客户端和服务器功能,网络传输模块基于boost::asio
提供 server 功能的 websocketpp::server 和提供 client 功能的 websocketpp:client 都继承自基类 websocketpp::endpoint , endpoint提供了一些通用的功能函数:
void set_access_channels(log::level channels);//设置日志级别
void clear_access_channels(log::level channels)//屏蔽某个级别的日志
void set_open_handler(open_handler h);//设置打开连接时的回调函数
void set_close_handler(close_handler h);//设置关闭连接时的回调函数
void set_fail_handler(fail_handler h);//设置连接失败时的回调函数
void set_message_handler(message_handler h);//设置收到消息时的回调函数
服务器代码
#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>
#include <functional>
typedef websocketpp::server<websocketpp::config::asio> server;
class utility_server {
public:
utility_server() {
// 设置log
m_endpoint.set_error_channels(websocketpp::log::elevel::all);
m_endpoint.set_access_channels(websocketpp::log::alevel::all ^ websocketpp::log::alevel::frame_payload);
// 初始化Asio
m_endpoint.init_asio();
// 设置消息回调为echo_handler
m_endpoint.set_message_handler(std::bind(
&utility_server::echo_handler, this,
std::placeholders::_1, std::placeholders::_2
));
}
void echo_handler(websocketpp::connection_hdl hdl, server::message_ptr msg) {
// 发送消息
m_endpoint.send(hdl, msg->get_payload(), msg->get_opcode());
}
void run() {
// 监听端口 9002
m_endpoint.listen(9002);
m_endpoint.start_accept();
// 开始Asio事件循环
m_endpoint.run();
}
private:
server m_endpoint;
};
int main() {
utility_server s;
s.run();
return 0;
}
运行后执行到 s.run() 当前线程会进入Asio的消息循环,可以调用s.top()退出
客户端代码
#include <websocketpp/config/asio_no_tls_client.hpp>
#include <websocketpp/client.hpp>
#include <iostream>
typedef websocketpp::client<websocketpp::config::asio_client> client;
using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
using websocketpp::lib::bind;
typedef websocketpp::config::asio_client::message_type::ptr message_ptr;
void on_open(client *c, websocketpp::connection_hdl hdl)
{
std::string msg = "hello";
c->send(hdl, msg, websocketpp::frame::opcode::text);
c->get_alog().write(websocketpp::log::alevel::app, "Tx: " + msg);
}
void on_message(client *c, websocketpp::connection_hdl hdl, message_ptr msg)
{
std::cout << "on_message called with hdl: " << hdl.lock().get()
<< " and message: " << msg->get_payload()
<< std::endl;
websocketpp::lib::error_code ec;
//c->send(hdl,msg->get_payload(),msg->get_opcode(),ec);
if(ec)
{
std::cout << "Echo failed because " << ec.message() << std::endl;
}
}
//定时器回调函数
void Timeout(client *c, websocketpp::connection_hdl &hdl, boost::asio::deadline_timer *pt, const boost::system::error_code &ec)
{
if(ec)
{
std::cout << "timer is cancel " << std::endl;
return;
}
static int count = 0;
c->send(hdl, "hello", websocketpp::frame::opcode::text);
count++;
if(count > 5)//定时器触发五次后关闭连接
{
c->close(hdl, websocketpp::close::status::normal, "");
return;
}
pt->expires_at(pt->expires_at() + boost::posix_time::seconds(5));
pt->async_wait(bind(Timeout, c, hdl, pt, ::_1));
}
int main(int argc, char *argv[])
{
client c;
std::string uri = "ws://xx.xx.xx.xx:xxx";
c.set_access_channels(websocketpp::log::alevel::all);
c.clear_access_channels(websocketpp::log::alevel::frame_payload);
c.clear_access_channels(websocketpp::log::alevel::frame_header);
// 初始化 ASIO
c.init_asio();
// 注册消息回调
c.set_message_handler(bind(&on_message, &c, ::_1, ::_2));
c.set_open_handler(bind(&on_open, &c, _1));
websocketpp::lib::error_code ec;
client::connection_ptr con = c.get_connection(uri, ec);
con->add_subprotocol("janus-protocol");
if(ec)
{
std::cout << "could not create connection because: " << ec.message() << std::endl;
return 0;
}
auto hdl = con->get_handle();
c.connect(con);
boost::asio::deadline_timer t(c.get_io_service(), boost::posix_time::seconds(5)); //设置一个5s超时的定时器
t.async_wait(bind(&Timeout, &c, hdl, &t, ::_1));
std::thread th([&c] { c.run(); });
//休眠13s后取消定时器并关闭连接
sleep(13);
t.cancel();
c.close(hdl, websocketpp::close::status::normal, "");
th.join();
}
我们可以利用 Asio 的一些其它组件,如定时器等;初始化定时器传入 c.get_io_service() 在一个io循环中处理定时事件和其它事件
当客户端调用 close 关闭连接时,则自动退出c.run()开启的循环
重复关闭和打开连接
#include <websocketpp/config/asio_no_tls_client.hpp>
#include <websocketpp/client.hpp>
#include <iostream>
typedef websocketpp::client<websocketpp::config::asio_client> client;
using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
typedef websocketpp::config::asio_client::message_type::ptr message_ptr;
class connection
{
public:
void on_open(websocketpp::connection_hdl hdl)
{
std::string msg = "hello";
c.send(hdl, msg, websocketpp::frame::opcode::text);
c.get_alog().write(websocketpp::log::alevel::app, "Tx: " + msg);
}
void on_message(websocketpp::connection_hdl hdl, message_ptr msg)
{
std::cout << "on_message called with hdl: " << hdl.lock().get()
<< " and message: " << msg->get_payload()
<< std::endl;
websocketpp::lib::error_code ec;
if(ec)
{
std::cout << "Echo failed because " << ec.message() << std::endl;
}
}
int init()
{
uri = "ws://xx.xx.xx.xx:xx";
c.set_access_channels(websocketpp::log::alevel::all);
c.clear_access_channels(websocketpp::log::alevel::frame_payload);
c.clear_access_channels(websocketpp::log::alevel::frame_header);
c.init_asio();
c.set_message_handler(websocketpp::lib::bind(&connection::on_message, this,::_1, ::_2));
c.set_open_handler(websocketpp::lib::bind(&connection::on_open, this, _1));
c.start_perpetual();
thread_=websocketpp::lib::make_shared<websocketpp::lib::thread>(&client::run,&c);
}
void connect()
{
websocketpp::lib::error_code ec;
client::connection_ptr con = c.get_connection(uri, ec);
if(ec)
{
std::cout << "could not create connection because: " << ec.message() << std::endl;
return ;
}
hdl_ = con->get_handle();
c.connect(con);
}
void close()
{
c.close(hdl_, websocketpp::close::status::normal, "");
}
void terminate()
{
c.stop_perpetual();
thread_->join();
}
private:
client c;
websocketpp::lib::shared_ptr<websocketpp::lib::thread> thread_;
websocketpp::connection_hdl hdl_;
std::string uri;
};
需要重复打开关闭连接时,只调用一次init_asio()函数,然后调用start_perpetual()将endpoint设置为永久的,不会在连接断开时自动退出。需要结束循环,调用stop_perpetual()
使用websocketpp进行websocket通信的更多相关文章
- C#(SuperWebSocket)与websocket通信
原文:C#(SuperWebSocket)与websocket通信 客户端代码 点击可以查看一些关于websocket的介绍 <!DOCTYPE html> <html> &l ...
- js判断是否安装某个android app,没有安装下载该应用(websocket通信,监听窗口失去焦点事件)
现在经常有写场景需要提示用户下载app, 但是如果用户已经安装,我们希望是直接打开app. 实际上,js是没有判断app是否已经安装的方法的,我们只能曲线救国. 首先,我们需要有call起app的sc ...
- Springboot集成WebSocket通信全部代码,即扣即用。
websocket通信主要来自两个类以及一个测试的html页面. MyHandler 和 WebSocketH5Config,下面全部代码 MyHandler类全部代码: package com.un ...
- 【Java Web开发学习】Spring MVC整合WebSocket通信
Spring MVC整合WebSocket通信 目录 ========================================================================= ...
- websocket通信1009错误,
问题说明: springboot继承 WebSocketConfigurer实现websocket通信服务,服务器端报错,"The decoded text message was too ...
- Python3+WebSockets实现WebSocket通信
一.说明 1.1 背景说明 前段时间同事说云平台通信使用了个websocket的东西,今天抽空来看一下具体是怎么个通信过程. 从形式上看,websocket是一个应用层协议,socket是数据链路层. ...
- webSocket通信
针对webSocket通信总结: 1.webSocket通信原理图: 2.webSocket通信实例 参考地址1:https://www.cnblogs.com/cjm123/p/9674506.ht ...
- 把酒言欢话聊天,基于Vue3.0+Tornado6.1+Redis发布订阅(pubsub)模式打造异步非阻塞(aioredis)实时(websocket)通信聊天系统
原文转载自「刘悦的技术博客」https://v3u.cn/a_id_202 "表达欲"是人类成长史上的强大"源动力",恩格斯早就直截了当地指出,处在蒙昧时代即低 ...
- websocket通信 实现java模拟一个client与webclient通信
发文原由: 熟悉socket通信的同学,对于socket模拟server与client,实现相互通信, 或者使用websocket与java模拟的websocket服务器通信(比如一个聊天室),对于这 ...
随机推荐
- 【CJOJ】为了博多
Description 做了个噩梦,梦见我的 n 把刀到60级会二次变身,变成一个 对推6图有xi点贡献,刷大阪城有yi点贡献 的刀,于是要把刀分成两队一队刷大阪城另一队推6图 . 但是有m对兄弟刀在 ...
- django-Xadmin后台管理
0919自我总结 django-Xadmin后台管理 一.安装环境 pip install https://codeload.github.com/sshwsfc/xadmin/zip/django2 ...
- Java编程思想——第17章 容器深入研究 读书笔记(二)
五.List的功能方法 排除Collection已包含的方法外还增加了 boolean addAll(int index, Collection<? extends E> c);从索引位置 ...
- PHP 数组转json格式,key的保存问题
<?php $arr = [ 2, 3, ]; echo print_r($arr,true); echo json_encode($arr); echo "\n\n"; $ ...
- [JZOJ5459]【NOIP2017提高A组冲刺11.7】密室
Description 小X 正困在一个密室里,他希望尽快逃出密室.密室中有N 个房间,初始时,小X 在1 号房间,而出口在N 号房间.密室的每一个房间中可能有着一些钥匙和一些传送门,一个传送门会单向 ...
- 浑身尖刺的服务可用性守护者——hystrix熔断器实践记录
netflix公司的产品hystrix(长满刺的豪猪),在高可用目标下具有一定熔断.限流.降级的作用.这里主要写一些自己在使用时的问题解决思路,原理请自行理解,包括线程池与信号量模式等. 注意三个参数 ...
- 【RabbitMQ 实战指南】一 死信队列
1.死信队列 DLX,全称为 Dead-Letter-Exchange,可以称之为死信交换器.当消息在一个队列中变成死信(dead message)之后,它能被发送到另一个交换器中,这个交换器就是DL ...
- CentOS7使用‘中科大源’
中科大的源质量速度都不错,推荐使用. 这里列出CentOS 7的Base和epel的源. 进入/etc/yum.repos.d/中,将原本的几个repo文件备份,之后新建三个repo文件 内容如下: ...
- git clone下代码window与unix换行问题
项目中避免不了会写一些shell脚本,使用ln软连接到一个目录.当git clone到windows中,ln连接显示无比怪异(如../xx),打开.sh文件后(仅仅是打开了),git status会看 ...
- 时序数据库InfluxDB(I)- 搭建与采集信息demo操作
搭建环境:vmware workstation pro15.5.0, ubuntu18.04.3 实践时间:2019.10.12-10.27 (一)时序数据库InfluxDB准备 (1)安装 曾出现问 ...