其他链接
上次使用了go来制作微服务计算服务
go制作微服务计算服务
c++制作标准差服务计算
使用c++的计算服务速度是更快的,一下只是一个计算标准差的函数样例,和go服务之间进行交换可以使用更简单的c,如果使用c++,则可以简化计算过程
#pragma once
#include <vector>
//标准差
//数据是五分钟的,就是sdann
//数据是24小时的,就是sdnn
double get_stddev(std::vector<double> &data);
double get_average(std::vector <double> &data);
cpp如下
double get_stddev(std::vector<double> &data)
{
double ret = 0.0;
size_t size = data.size();
if (size == 0)
return -1;
double sum = std::accumulate(std::begin(data), std::end(data), 0.0);
double mean = sum / (double)size; //均值
std::cout << "the mean is " << mean << std::endl;
double sdnn_2 = 0.0;
std::for_each(std::begin(data), std::end(data), [&](const double d) {
sdnn_2 += (d - mean)*(d - mean);
});
double sdnn = sqrt(sdnn_2 / (size)); //方
return sdnn;
}
//求取均值
double get_average(std::vector <double> &data)
{
size_t size = data.size();
if (size == 0)
return -1;
double sum = std::accumulate(std::begin(data), std::end(data), 0.0);
double mean = sum / (double)size; //均值
return mean;
}
c++ http服务 ws服务
使用c++ boost库制作携程服务器,具体我的其他文章里面有
一下是http和ws 服务的c++携程代码,包含了http协议的基本和websocket 协议的基本
#include <boost/asio.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/steady_timer.hpp>
#include <boost/asio/write.hpp>
#include <boost/uuid/detail/sha1.hpp>
#include <iostream>
#include <memory>
#include "util.h"
#include "util_flv_pack.h"
#include "util_hash.h"
#include "c_hub.h"
#define DEFINE_EC \
boost::system::error_code ec;
#define ERROR_RETURN_FALSE \
if(ec){\
std::cout << ec.message() << std::endl;\
return false;\
}
#define ERROR_RETURN \
if(ec){ \
std::cout << ec.message() << std::endl;\
return ;\
}
#define ERROR_BREAK(ec) \
if (ec){ \
close();\
std::cout << ec.message() << std::endl;\
break;\
}
using namespace boost;
using boost::asio::ip::tcp;
typedef enum en_data_type
{
en_text = 1,
en_binary,
en_ping = 0x09,
en_pong = 0x0A
}en_data_type;
//the mem has reserved some room for set something,
//1 is must reserved something for ws head
//2 is must reserved something for user protocol head
typedef void (*cb_wsdata)(en_data_type type,uint8_t *mem, uint8_t* data, size_t len);
class c_session_webs : public std::enable_shared_from_this<c_session_webs>
{
private:
void SetSendBufferSize(int nSize)
{
boost::asio::socket_base::send_buffer_size size_option(nSize);
v_socket.set_option(size_option);
}
void SetRecvBufferSize(int nSize)
{
boost::asio::socket_base::receive_buffer_size size_option(nSize);
v_socket.set_option(size_option);
}
public:
//do not need this ,we just need key
//std::string v_app_stream;
uint32_t v_key = 0;
//time stamp record,every one not the same
uint32_t v_start_ts = 0;
bool v_iswebsocket = false;
public:
explicit c_session_webs(boost::asio::io_context& io_context, tcp::socket socket)
: v_socket(std::move(socket)),
/*timer_(io_context),*/
v_strand(io_context.get_executor())
{
#ifdef _WIN32
SetSendBufferSize(1 * 1024 * 1024);
SetRecvBufferSize(64 * 1024);
#endif
}
/*
The handshake from the client looks as follows :
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
GET /chat HTTP/1.1
Host: 127.0.0.1:9000
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket
Origin: file://
Sec-WebSocket-Version: 13
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.8
Sec-WebSocket-Key: 1M9Y1T8iMgTLepYQGDFoxg==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
*/
void func_hand_http(c_header_map &m, boost::asio::yield_context &yield);
bool func_hand_shake(boost::asio::yield_context &yield)
{
int fret = -1;
DEFINE_EC
asio::streambuf content_;
size_t length = asio::async_read_until(v_socket, content_, "\r\n\r\n", yield[ec]);
ERROR_RETURN_FALSE
asio::streambuf::const_buffers_type bufs = content_.data();
std::string lines(asio::buffers_begin(bufs), asio::buffers_begin(bufs) + length);
c_header_map m;
string query; // GET /live/1001 => the query is live/1001
if (fetch_head_info(lines, m, query) == -1) //NOT GET or http protocol
return false;
//v_key is the hash value
v_key = hash_add(query.c_str(), HASH_PRIME_MIDDLE);
auto iter = m.find("Upgrade");
if (iter == m.end()) //ishttp
{
//it is the http protocol ,but not websocket
func_hand_http(m,yield);
size_t ret = boost::asio::async_write(v_socket, boost::asio::buffer(FLV_HTTP_HEADERS, FLV_HTTP_HEADERS_LEN), yield[ec]);
ERROR_RETURN_FALSE
if (c_flvhubs::instance()->push_session(v_key, shared_from_this(), true) == NULL)
{
//we can not find the stream
return false;
}
return true;
}
else
{
//is websocket protocol
v_iswebsocket = true;
std::string response, key, encrypted_key;
//find the get
//std::string request;
size_t n = lines.find_first_of('\r');
//find the Sec-WebSocket-Key
size_t pos = lines.find("Sec-WebSocket-Key");
if (pos == lines.npos)
return false;
size_t end = lines.find("\r\n", pos);
key = lines.substr(pos + 19, end - pos - 19) + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
//get the base64 encode string with sha1
#if 1
boost::uuids::detail::sha1 sha1;
sha1.process_bytes(key.c_str(), key.size());
#endif
#if 0
SHA1 sha;
unsigned int message_digest[5];
sha.Reset();
sha << server_key.c_str();
sha.Result(message_digest);
#endif
unsigned int digest[5];
sha1.get_digest(digest);
for (int i = 0; i < 5; i++) {
digest[i] = htonl(digest[i]);
}
encrypted_key = base64_encode(reinterpret_cast<const uint8_t*>(&digest[0]), 20);
/*
The handshake from the server looks as follows :
HTTP / 1.1 101 Switching Protocols
Upgrade : websocket
Connection : Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK + xOo =
Sec-WebSocket-Protocol: chat
*/
//set the response text
response.append("HTTP/1.1 101 WebSocket Protocol Handshake\r\n");
response.append("Upgrade: websocket\r\n");
response.append("Connection: Upgrade\r\n");
response.append("Sec-WebSocket-Accept: " + encrypted_key + "\r\n\r\n");
//response.append("Sec-WebSocket-Protocol: chat\r\n");
//response.append("Sec-WebSocket-Version: 13\r\n\r\n");
size_t ret = boost::asio::async_write(v_socket, boost::asio::buffer(response), yield[ec]);
ERROR_RETURN_FALSE
c_flvhubs::instance()->push_session(v_key, shared_from_this());
}
//calculate the hash key
return true;
}
bool func_set_head_send(uint8_t * frame, int len /*payloadlen*/, int framelen, asio::yield_context &yield)
{
*frame = 0x81;//0x81; 1000 0001 text code ; // 1000 0010 binary code
//*frame = 0x82;
if (len <= 125) {
//数据长度小于1个字节
//mask bit is 0
*(frame + 1) = (uint8_t)len;
}
else if (len <= 0xFFFF) { //65535
//数据长度小于2个字节
*(frame + 1) = 126;
*(frame + 2) = len & 0x000000FF;
*(frame + 3) = (len & 0x0000FF00) >> 8;
}
else {
//数据长度为8个字节
*(frame + 1) = 127;
*(frame + 2) = len & 0x000000FF;
*(frame + 3) = (len & 0x0000FF00) >> 8;
*(frame + 4) = (len & 0x00FF0000) >> 16;
*(frame + 5) = (len & 0xFF000000) >> 24;
*(frame + 6) = 0;
*(frame + 7) = 0;
*(frame + 8) = 0;
*(frame + 9) = 0;
}
DEFINE_EC
//send the data
asio::async_write(v_socket, asio::buffer(frame, framelen), yield[ec]);
if (ec)
{
return false;
}
return true;
}
bool func_recv_message(asio::yield_context &yield)
{
/* RFC 6455
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len | Extended payload length |
|I|S|S|S| (4) |A| (7) | (16/64) |
|N|V|V|V| |S| | (if payload len==126/127) |
| |1|2|3| |K| | |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
| Extended payload length continued, if payload len == 127 |
+ - - - - - - - - - - - - - - - +-------------------------------+
| |Masking-key, if MASK set to 1 |
+-------------------------------+-------------------------------+
| Masking-key (continued) | Payload Data |
+-------------------------------- - - - - - - - - - - - - - - - +
: Payload Data continued ... :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Payload Data continued ... |
+---------------------------------------------------------------+
*/
DEFINE_EC
unsigned char code[2];
size_t n = asio::async_read(v_socket, asio::buffer(&code[0], sizeof(code)), yield[ec]);
ERROR_RETURN_FALSE
unsigned char fin = code[0] >> 7;
unsigned char opcode = code[0] & 0x0f; //00001111 //opcode four bit
if (fin == char(0x00))
{
//1 the message's last fragment
//0 not the last fragment
return false;
}
switch (opcode)
{
case 0x01:
//a text frame
case 0x02:
//a binary frame
break;
case 0x08:
//%x8 denotes a connection close rfc6455
std::cout << "connection close" << std::endl;
return false;
case 0x09://WebSocket服务端向客户端发送ping,服务与服务之间可以发送保持链接
//denotes a ping
std::cout << "a ping come" << std::endl;
return true;
case 0x0A:
//denotes a pong
std::cout << "a pong come" << std::endl;
return true;
default:
return false;
}
en_data_type type = (en_data_type)opcode;
unsigned char is_mask = code[1] >> 7;
//x is 0~126:payload len is x bytes //数据的长度为x字节。
//x is 126:the conitnue 2 bytes is unsigned uint16 number ,this number is payload length //该无符号整数的值为数据的长度。
//x is 127:the continue 8 bytes is unsigned uint64 number ,this number is payload length //后续8个字节代表一个64位的无符号整数(最高位为0),该无符号整数的值为数据的长度。
//qianbo : when send data , we must reserve the room for real data
int reserved_len = 1;
uint64_t payloadlen = code[1] & 0x7F;
if (payloadlen == 0x7E) //0111 1110
{
uint16_t len;
asio::async_read(v_socket, asio::buffer(&len, sizeof(len)), yield[ec]);
ERROR_RETURN_FALSE
payloadlen = ntohs(len);
reserved_len += 3;
}
else if (payloadlen == 0x7F) //0111 1111
{
uint64_t len;
asio::async_read(v_socket, asio::buffer(&len, sizeof(len)), yield[ec]);
ERROR_RETURN_FALSE
payloadlen = ntohll_1(len);
reserved_len += 9;
}
else
{ //qianbo <126 bytes
//if(payloadlen < 126)
reserved_len += 1;
}
//get mask if exists
char mask[4];
if (is_mask)
{
asio::async_read(v_socket, asio::buffer(mask, 4), yield[ec]);
ERROR_RETURN_FALSE
}
if (payloadlen > 0)
{
//the datalen + ws head len + reserved protocol len
size_t frame_len = (payloadlen + reserved_len/* + v_respro_len*/);
uint8_t *frame = new uint8_t[frame_len];
uint8_t *data = frame + reserved_len /*+ v_respro_len*/;
asio::async_read(v_socket, asio::buffer(data, payloadlen), yield[ec]);
ERROR_RETURN_FALSE
if (is_mask)
{
//get the real data
for (uint64_t i = 0; i < payloadlen; i++)
{
data[i] = data[i] ^ mask[i % 4];
}
}
//data[payloadlen] = '\0';
//std::cout << data << std::endl;
if (v_cb != NULL)
v_cb(type, frame, data, frame_len);
//echo ,send back to session
//func_set_head_send(frame, payloadlen, frame_len, yield);
delete[] frame;
}
return true;
}
void go()
{
auto self(shared_from_this());
boost::asio::spawn(v_strand,
[this, self](boost::asio::yield_context yield)
{
//try
//{
//timer_.expires_from_now(std::chrono::seconds(10));
if (func_hand_shake(yield) == false)
{
std::cout << "not hand shake" << std::endl;
return;
}
for (;;)
{
bool ret = func_recv_message(yield);
if (!ret)
{
close();
break;
}
}
//}
//catch (std::exception& e)
//{
// std::cout << "some is error:" << e.what() << std::endl;
// close();
// //timer_.cancel();
//}
});
}
void func_setcb(cb_wsdata cb, int len)
{
v_cb = cb;
}
protected:
//asio::steady_timer timer_;
asio::io_context v_ioctx;
asio::strand<boost::asio::io_context::executor_type> v_strand;
cb_wsdata v_cb = NULL;
std::string v_get;//like /live/1001
public:
tcp::socket v_socket;
//has end meta data
int v_has_send_meta = 0;
//stream have video ?
uint8_t v_has_video = 0;
//stream have audio?
uint8_t v_has_audio = 0;
//was send video head meta
int v_has_send_video_head = 0;
//was send audio head meta
int v_has_send_audio_head = 0;
//was send key frame
int v_has_sent_key_frame = 0;
void close()
{
if (v_socket.is_open())
v_socket.close();
}
};
util.h
用到的解析http的部分函数
/*
lines :http protocol content lines =>GET /live/1001
buf :let the url into this buffer => live/1001
buflen:the buf's length
*/
static int fetch_head_get(const char * lines, char *buf,int buflen)
{
size_t l = strlen(lines);
if (l < 6)
return 0;
//it is GET protocol
if (strncmp(lines, "GET ", 4) != 0)
return -1;
char *pos = buf;
//URL->GET /live/image ==> get the live/image to buf
#if 0
char *ori = (char*)&lines[5];
while (*(ori++) != ' ');
size_t num = --ori - (lines + 5);
#endif
#define START_P 5
for (size_t i = START_P; i < l,i<buflen+ START_P; i++)
{
if (lines[i] == ' ')
break;
*pos++ = lines[i];
}
*pos = '\0';
return (int)(pos-buf);
}
//ret is the /chat like this
// we must add the post protocol
static int fetch_head_info(std::string &lines, c_header_map &hmap, std::string &ret)
{
if (strncmp(lines.c_str(), "GET ", 4) != 0)
return -1;
//not support now
if (strncmp(lines.c_str(), "POST ", 5 == 0))
return -2;
std::istringstream s(lines);
std::string request;
std::getline(s, request);
if (request[request.size() - 1] == '\r')
{
request.pop_back();
//request.erase(request.end() - 1);//the same with pop_back
//GET /chat HTTP/1.1
size_t i= 5;
size_t lmax = request.size();
while (request[++i] != ' ' && i<lmax);
if (i == lmax - 1)
return -1;
ret = request.substr(5, i - 5);
}
else
return -1;
hmap.clear();
std::string header;
std::string::size_type end;
while (std::getline(s, header) && header != "\r")
{
if (header[header.size() - 1] == '\r')
{
//header.pop_back(); //or use this function
header.erase(header.end() - 1); //remove last char
end = header.find(": ", 0);
if (end != std::string::npos)
{
std::string key = header.substr(0, end);
std::string value = header.substr(end + 2);
hmap[key] = value;
}
}
}
return 0;
}