dtcms 模板下载 history rinetd 云计算架构 reactjs file tkinter neo4j ios7 notifications ios4 sms android开发项目 click事件 jq解析json mysql默认密码 最新更新国内最快的dns java多行注释 java清空数组 arraylist删除指定元素 java手机验证码 eclipse显示左边目录 python循环 python入门教程 python异常 python正则表达 python返回值 java程序 java操作数据库 java语言是什么 java格式化日期 超级煎蛋卷 蒙文字体 pdf拆分工具 脚本大全 生存猎人属性 野德天赋 微信骰子表情包 VSPD 只狼台词
当前位置: 首页 > 学习教程  > 

使用restbed库-websocket

2020/10/16 17:48:15 文章标签: websocket库

http 通常只是一种client/server的通信方式,只能由client 请求时,服务器端才能够向client发送响应数据。这在某些场合是不方便的。比如在嵌入式系统的web服务器中,服务器需要将硬件采集的数据定时发送给客户端的HTML 界面上。这是可以使用web…

      http 通常只是一种client/server的通信方式,只能由client 请求时,服务器端才能够向client发送响应数据。这在某些场合是不方便的。比如在嵌入式系统的web服务器中,服务器需要将硬件采集的数据定时发送给客户端的HTML 界面上。这是可以使用websocket 机制。

   Websocket 建立浏览器和web服务器之间一个socket 连接。任何一方都可以在任何时候开始发送数据。

代码

该程序每隔2秒发送一个模拟温度的随机数到Client 端。

几点提示:

  1. 随机数产生

产生一个随机数据来模拟物理传感器的值。

#include <iostream>
#include <random>

using std::cout; using std::endl;
using std::default_random_engine;
using std::uniform_real_distribution;
    
int main()
{
    default_random_engine e; 
    uniform_real_distribution<double> u(0, 1); //随机数分布对象 
    for (size_t i = 0; i < 5; ++i)  //生成范围为0.0-1.0的随机数序列 
       cout << u(e) << " ";
    cout << endl;
    
    return 0;
}
  1. C++ 浮点数转string
#include <iomanip> // setprecision
#include <sstream> // stringstream

double pi = 3.14159265359;
stringstream stream;
stream << fixed << setprecision(2) << pi;
string s = stream.str();

 

服务器端C++

程序来源于:https://github.com/Corvusoft/restbed/blob/master/documentation/example/WEB_SOCKET.md

#include <map>
#include <chrono>
#include <string>
#include <cstring>
#include <iomanip> // setprecision cout
#include <memory>
#include <utility>
#include <cstdlib>
#include <fstream>
#include <restbed>
#include <system_error>
#include <openssl/sha.h>
#include <openssl/hmac.h>
#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
#include <random>
using namespace std;
using namespace restbed;
using namespace std::chrono;
using std::default_random_engine;
using std::uniform_real_distribution;
default_random_engine temperature; 
uniform_real_distribution<double> u(0, 1);

shared_ptr< Service > service = nullptr;
map< string, shared_ptr< WebSocket > > sockets = { };

string base64_encode( const unsigned char* input, int length )
{
    BIO* bmem, *b64;
    BUF_MEM* bptr;
    
    b64 = BIO_new( BIO_f_base64( ) );
    bmem = BIO_new( BIO_s_mem( ) );
    b64 = BIO_push( b64, bmem );
    BIO_write( b64, input, length );
    ( void ) BIO_flush( b64 );
    BIO_get_mem_ptr( b64, &bptr );
    
    char* buff = ( char* )malloc( bptr->length );
    memcpy( buff, bptr->data, bptr->length - 1 );
    buff[ bptr->length - 1 ] = 0;
    
    BIO_free_all( b64 );
    
    return buff;
}

multimap< string, string > build_websocket_handshake_response_headers( const shared_ptr< const Request >& request )
{
    auto key = request->get_header( "Sec-WebSocket-Key" );
    key.append( "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" );
    
    Byte hash[ SHA_DIGEST_LENGTH ];
    SHA1( reinterpret_cast< const unsigned char* >( key.data( ) ), key.length( ), hash );
    
    multimap< string, string > headers;
    headers.insert( make_pair( "Upgrade", "websocket" ) );
    headers.insert( make_pair( "Connection", "Upgrade" ) );
    headers.insert( make_pair( "Sec-WebSocket-Accept", base64_encode( hash, SHA_DIGEST_LENGTH ) ) );
    
    return headers;
}

void ping_handler( void )
{
    for ( auto entry : sockets )
    {
        auto key = entry.first;
        auto socket = entry.second;
        
        if ( socket->is_open( ) )
        {
            socket->send( WebSocketMessage::PING_FRAME );
        }
        else
        {
            socket->close( );
        }
    }
}
void data_handler( void )
{
    for ( auto entry : sockets )
    {
        auto key = entry.first;
        auto socket = entry.second;
        
        if ( socket->is_open( ) )
        {      stringstream stream;
	          stream << fixed << setprecision(2)<<u(temperature);
               socket->send( "Temperature:"+stream.str(), [ ]( const shared_ptr< WebSocket > socket )
                    {
                        const auto key = socket->get_key( );
                        sockets.insert( make_pair( key, socket ) );
                        
                        fprintf( stderr, "Send Data message to %s.\n", key.data( ) );
                    } );
        }
        else
        {
            socket->close( );
        }
    }
}
void close_handler( const shared_ptr< WebSocket > socket )
{
    if ( socket->is_open( ) )
    {
        auto response = make_shared< WebSocketMessage >( WebSocketMessage::CONNECTION_CLOSE_FRAME, Bytes( { 10, 00 } ) );
        socket->send( response );
    }
    
    const auto key = socket->get_key( );
    sockets.erase( key );
    
    fprintf( stderr, "Closed connection to %s.\n", key.data( ) );
}

void error_handler( const shared_ptr< WebSocket > socket, const error_code error )
{
    const auto key = socket->get_key( );
    fprintf( stderr, "WebSocket Errored '%s' for %s.\n", error.message( ).data( ), key.data( ) );
}

void message_handler( const shared_ptr< WebSocket > source, const shared_ptr< WebSocketMessage > message )
{
    const auto opcode = message->get_opcode( );
    
    if ( opcode == WebSocketMessage::PING_FRAME )
    {
        auto response = make_shared< WebSocketMessage >( WebSocketMessage::PONG_FRAME, message->get_data( ) );
        source->send( response );
    }
    else if ( opcode == WebSocketMessage::PONG_FRAME )
    {
        //Ignore PONG_FRAME.
        //
        //Every time the ping_handler is scheduled to run, it fires off a PING_FRAME to each
        //WebSocket. The client, if behaving correctly, will respond with a PONG_FRAME.
        //
        //On each occasion the underlying TCP socket sees any packet data transfer, whether
        //a PING, PONG, TEXT, or BINARY... frame. It will automatically reset the timeout counter
        //leaving the connection active; see also Settings::set_connection_timeout.
        return;
    }
    else if ( opcode == WebSocketMessage::CONNECTION_CLOSE_FRAME )
    {
        source->close( );
    }
    else if ( opcode == WebSocketMessage::BINARY_FRAME )
    {
        //We don't support binary data.
        auto response = make_shared< WebSocketMessage >( WebSocketMessage::CONNECTION_CLOSE_FRAME, Bytes( { 10, 03 } ) );
        source->send( response );
    }
    else if ( opcode == WebSocketMessage::TEXT_FRAME )
    {
        auto response = make_shared< WebSocketMessage >( *message );
        response->set_mask( 0 );
        
        for ( auto socket : sockets )
        {
            auto destination = socket.second;
            destination->send( response );
        }
        
        const auto key = source->get_key( );
        const auto data = String::format( "Received message '%.*s' from %s\n", message->get_data( ).size( ), message->get_data( ).data( ), key.data( ) );
        fprintf( stderr, "%s", data.data( ) );
    }
}

void get_method_handler( const shared_ptr< Session > session )
{
    const auto request = session->get_request( );
    const auto connection_header = request->get_header( "connection", String::lowercase );
    
    if ( connection_header.find( "upgrade" ) not_eq string::npos )
    {
        if ( request->get_header( "upgrade", String::lowercase ) == "websocket" )
        {
            const auto headers = build_websocket_handshake_response_headers( request );
            
            session->upgrade( SWITCHING_PROTOCOLS, headers, [ ]( const shared_ptr< WebSocket > socket )
            {
                if ( socket->is_open( ) )
                {
                    socket->set_close_handler( close_handler );
                    socket->set_error_handler( error_handler );
                    socket->set_message_handler( message_handler );
                    
                    socket->send( "Welcome to Corvusoft Chat!", [ ]( const shared_ptr< WebSocket > socket )
                    {
                        const auto key = socket->get_key( );
                        sockets.insert( make_pair( key, socket ) );
                        
                        fprintf( stderr, "Sent welcome message to %s.\n", key.data( ) );
                    } );
                }
                else
                {
                    fprintf( stderr, "WebSocket Negotiation Failed: Client closed connection.\n" );
                }
            } );
            
            return;
        }
    }
    
    session->close( BAD_REQUEST );
}
void get_index( const shared_ptr< Session > session )
{
   // const auto request = session->get_request( );
    
    ifstream stream( "./views/websocketClient.html", ifstream::in );
    
    if ( stream.is_open( ) )
    {
        const string body = string( istreambuf_iterator< char >( stream ), istreambuf_iterator< char >( ) );
        
        const multimap< string, string > headers
        {
            { "Content-Type", "text/html" },
            { "Content-Length", ::to_string( body.length( ) ) }
        };
        
        session->close( OK, body, headers );
    }
    else
    {
        session->close( NOT_FOUND );
    }
}
int main( const int, const char** )
{
    auto resource = make_shared< Resource >( );
    resource->set_path( "/chat" );
    resource->set_method_handler( "GET", get_method_handler );
  
   auto resource1 = make_shared< Resource >( );	  
    resource1->set_path( "/index" );
    resource1->set_method_handler( "GET", get_index );
    auto settings = make_shared< Settings >( );
    settings->set_port( 1984 );
    
    service = make_shared< Service >( );
    service->publish( resource );
	service->publish( resource1 );
    //service->schedule( ping_handler, milliseconds( 5000 ) );
	service->schedule( data_handler, milliseconds( 2000 ) );
    service->start( settings );
    
    return EXIT_SUCCESS;
}

client 端的html/javascript

<!DOCTYPE HTML>
<html lang="en" dir="ltr">
 <head>
    <meta charset="utf-8">
    <style>
      html, body {
        margin: 0;
      }

      ul {
        list-style: none;
      }

      li {
         text-align: left;
      }

      input {
        width: 40%;
        height: 40px;
        line-height: 40px;
        margin-bottom: 10px;
      }

      a {
        margin: 10px;
      }

      .disabled {
        color: #000;
        pointer-events: none;
      }

      #controls {
        width: 100%;
        bottom: 10%;
        position: absolute;
        text-align: center;
      }
    </style>
    <script type="text/javascript">
      function on_return_submit( evt )
      {
         if ( window.restbed.ws === null || window.restbed.ws.readyState !== window.restbed.ws.OPEN )
         {
            return;
         }

         if( evt && evt.keyCode == 13 )
         {
            var message = document.getElementById( "message" );
            window.restbed.ws.send( message.value );

            message.value = "";
         }
      }

      function toggle_control_access( )
      {
         var open = document.getElementById( "open" );
         open.disabled = !open.disabled;

         var message = document.getElementById( "message" );
         message.disabled = !message.disabled;

         var close = document.getElementById( "close" );
         close.className = ( close.className === "disabled" ) ? "" : "disabled";
      }

      function add_message( message )
      {
         var li = document.createElement( "li" );
         li.appendChild( document.createTextNode( "> " + message ) );

         var ul = document.getElementById( "messages" );
         ul.appendChild( li );
      }

      function open( )
      {
         if ( "WebSocket" in window )
         {
            var ws = new WebSocket( "ws://localhost:1984/chat" );

            ws.onopen = function( )
            {
               add_message( "Established connection." );

               toggle_control_access( );
            };

            ws.onmessage = function( evt )
            {
              //add_message( evt.data );
			  document.getElementById('value').innerHTML=evt.data;
            };

            ws.onclose = function( evt )
            {
               add_message( "Connection closed with RFC6455 code " + evt.code + "." );

               toggle_control_access( );
            };

            ws.onerror = function( evt )
            {
               add_message( "Error: socket connection interrupted." );
            };

            window.restbed.ws = ws;
         }
         else
         {
            alert( "WebSockets NOT supported by your Browser!" );
         }
      }

      function close( )
      {
         window.restbed.ws.close( );
      }

      ( function( )
      {
         window.restbed = { ws: null };
      } )( );
    </script>
  </head>
  <body>
  <h2>restbed webSocket example</h1>
   <p span id="value">0</p>
     <div>
       <ul id="messages"></ul>
       <div id="controls">
         <input id="message" type="text" onKeyPress="return on_return_submit( event )" disabled/>
         <div>
           <a id="open" href="javascript:open( )">Open Chat</a>
           <a id="close" href="javascript:close( )" class="disabled">Close Chat</a>
         <div>
       </div>
     </div>
  </body>
</html>

 


本文链接: http://www.dtmao.cc/news_show_300159.shtml

附件下载

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?