欢迎光临!欢迎分享转载本站文章,尊重原创,转载请注明出处!

Boost LRU-Cache使用方法简介

2017年11月13日 没有评论

    缓存是提高系统运行效率的常用组件,可以将“有效的”业务数据直接返回用户,避免繁琐的计算过程。除了Redis、MemCache等常用缓存系统,应用程序内部也可以根据需要设置一定容量的缓存,减少跨进程调用,提高效率。

    LRU是常用的缓存策略,可以将访问最 频繁的数据保存在有限的缓存中,提高缓存命中率。

    在C++中,可以通过map来保存数据键值对,并通过list将最近使用的数据保存在一端,从list的另一端来清除过期数据的方法实现一个缓存系统。

    然而,我们没必要自己再造一个轮子。Boost-1.65.1版本开始引入了lru_cache算法,通过模板的方式可以方便的实例化出各种类型的缓存对象。

    下面简单介绍boost lru_cache的使用方法。

#lru_cache头文件,这是个header-only库,不需要其他模块
#include <string>
#include <iostream>
using namespace std;
#include <boost/compute/detail/lru_cache.hpp>

int main()
{
    const int iCacheSize=100;
    #初始化时设置缓存容量
    boost::compute::detail::lru_cache<string, string> ssCache(iCacheSize);

    #插入数据
    ssCache.insert("ZhangSan", "Beijing");
    ssCache.insert("LiSi", "Shanghai");

    #查找并获取数据
    string s("ZhangSan");
    if(ssCache.contains(s))
    {
        #注意!get方法返回的是一个boost::optional<string>对象,而不是直接返回存入其中的Value类型的对象!
        boost::optional<string> o_Region=ssCache.get(s);
        #我们可以通过boost::optional<string>的get()来获取Value对象
        string sRegion=o_Region.get();
        cout << s << " comes from " << sRegion << endl;
    }

    return 0;
}
分类: C/C++, 开发 标签: , ,

Shell字符串分割与随机访问

2017年11月10日 没有评论

    Shell经常做的一项工作就是文本处理,通过组合grep、awk、sed等来实现查找、分割、替换、删除等操作。今天说一下对单行字符串的分割处理方法。先看代码:

_uas="Mozilla/5.0 (Linux; Android 5.1.1; Redmi Note 3) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/41.0.2272.96 Mobile Safari/535.19|Mozilla/5.0 (Linux; Android 4.4.4; 2014813) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/41.0.2272.96 Mobile Safari/535.19|Linux; Android 6.0.1; SM-G9008W) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/41.0.2272.96 Mobile Safari/535.19|Mozilla/5.0 (Linux; Android 5.0.2; Redmi Note 2) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/41.0.2272.96 Mobile Safari/535.19"

#生成随机索引
_rand_index=$(expr $RANDOM % 4) 

#设置新的分隔符
OLD_IFS="$IFS"
IFS="|" 
#将UA字符串分割到_arr数组中
_arr=($_uas) 
IFS="$OLD_IFS"

#通过下标访问数组中的元素。
_ua=${_arr[$_rand_index]}

    _uas包含以竖线|分隔的4个安卓UA,我想要随机取其中的一个UA来用。这涉及到两点需求:生成一个随机索引,将字符串按照指定的分隔符来分隔。

    Shell生成随机数的方法可以如上面代码一样直接取系统环境变量$RANDOM也可以通过date +%s的方法获取当前的秒数,再和数组长度取模来实现。当然通过系统时间的方法获得的随机数有可能并不很随机,特别是在操作间隔很短的情况下。

    单行字符串分割可以通过awk来实现,然后分别打印各列的值。但是通过设置系统IFS的方法看起来更直接,能够直接通过($string_line)将元素保存在新的数组中,这样就可以以下标的方式来访问。

    Shell还是博大精深的,不常用不足以体会其便捷与强大。

分类: Shell, 开发 标签: ,

python3 PyMySQL模块的安装和使用

2017年10月24日 没有评论

我们知道Python3和Python2是不兼容的,版本由2升级到3之后对MySQL数据库的访问也需要使用新的模块。此前的文章中已介绍过MySQLdb在Python2中的用法,今天介绍PyMySQL在Python3中的用法。

  1. 安装
    • 直接通过pip安装:
      pip install PyMySQL
  2. 示例
    • 连接数据库
    import pymysql
    try:
        conn = pymysql.connect(ip, 3306, user, password, db, charset='utf8', cursorclass=pymysql.cursors.DictCursor)
    except Exception as e:
        print("Exception throwed when connect to db: " + str(e))
    • 插入数据
      try:
          with conn.cursor() as cursor:
              sql = "insert into t_student(id, name) values (%d, %s)"
              rows=cursor.execute(sql, (s.id, s.name))
              conn.commit()
      
              if rows == 1:
                  print("Inserted.")
              else:
                  print("Failed")
      except Exception as e:
          print("Exception throwed when insert data: " + str(e))
分类: mysql, Python, 开发 标签: , ,

c++点滴:string非空判断和随机访问的实现细节和使用方法

2017年10月17日 没有评论
  1. 非空判断
    • 一般通过是否等于”” 或者empty()函数的返回值来判断是否为空,结果是一致的
    • 差别在于:empty()返回的是string内置变量_M_rep()->_M_length的值,不需要其他计算;而与””比较是需要调用compare(const _CharT* __s)函数来判断的,因此在性能方面,empty()更占优
  2. 随机访问
    • 可通过[]或at()来随机访问,都是通过下标直接访问内部buffer,很快。_M_data()[__pos]
    • 差别在于:at()更安全。当下标超出string.size()时,at()抛出异常,而[]则引发断言错误。
分类: C/C++, 开发 标签:

分享一段解析HTTP请求消息头的C++代码

2017年10月16日 没有评论

Http请求消息说白了就是\r\n和:分割的一串字符,解析消息头部考察的是基本的字符串操作。当然实际应用中可以使用boost::splitl来辅助处理。

请求消息如下:

GET /suggest?word=http://t.&callback=suggest360&encodein=utf-8&encodeout=utf-8&_h=18.js&outfmt=json HTTP/1.1
Host: sug.so.360.cn:8188
Cache-Control: no-cache
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36 QIHU 360SE
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8
Accept: */*
Cookie: vjuids=a8f919aab.156c5a83b9b.0.3db0cfd7; shenhui12=w:1; gn12=w:1; sci12=w:1; UM_distinctid=15c7168d4207f-083dc20ce-4349052c-100200-15c7168d42346; sohutag=8HsmeSc5NSwmcyc5NSwmYjc5MSwmYSc5NywmZjc5NCwmZyc5NCwmbjc5NjwmaSc5NSwmdyc5NCwmaCc5NCwmYyc5NCwmZSc5NCwmbSc5NCwmdCc5NH0; _muid_=1501816572977065; _ga=GA1.2.1163329499.1503043055; beans_mz_userid=62mbb0GPSAy5; debug_test=sohu_third_cookie; lastpopup=2017-8-19; vjlast=1472194952.1505800087.21; IPLOC=CN1100; SUV=1608221725397504
Range: bytes=17276560-19912545
Referer: http://offp.download.icartoons.cn:8188/client_package/v_4125/7825

解析代码如下:

//存储请求行
string cmdLine="";  
//存储消息头各字段和值
map<string, string> kvs;  

size_t pos=0, posk=0, posv=0;
string k="", v="";
char c;
//http保存了上述GET请求
while(pos != http.size())  
{
    c=http.at(pos);
    if(c == ':')
    {
        //非请求行,且消息头名称未解析
        if(!cmdLine.empty() && k.empty())  
        {
            //存储消息头名称
            k = http.substr(posk, pos-posk);  
            //跳过冒号和空格
            posv = pos+2;  
        }
    }
    //行尾
    else if(c == '\r' || c=='\n')  
    {
        //尚未解析到消息头字段名称,且请求行也未解析过
        if(k.empty() && cmdLine.empty())  
        {
            //本行应是请求行,保存之
            cmdLine = http.substr(posk, pos-posk);  
        }
        else
        {
            //已解析了消息头字段名称,尚未解析字段值
            if(!k.empty() && v.empty())  
            {
                //存储字段值
                v = http.substr(posv, pos-posv);  
            }
        }
        posk=pos+1;
    }

    if(!k.empty() && !v.empty() && !cmdLine.empty())
    {
        //保存消息头字段名称和值
        kvs.insert(make_pair(k,v));  
        k="";
        v="";
    }
    ++pos;
}

需要注意的是:消息头各字段的值中也有可能出现冒号。

分类: C/C++, 开发 标签: ,

pyquery:Python版的jQuery,HTML页面解析好工具

2017年9月20日 没有评论
# coding=utf-8

import requests
from pyquery import PyQuery as pq

#set request header
head_req = {
'User-Agent':'Mozilla/5.0 (Linux; U; Android 4.3; en-us; SM-N900T Build/JSS15J) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30',
'Referer':'http://www.baidu.com/'
}

url = 'http://zhixing.bjtu.edu.cn/portal.php'
r = requests.get(url, headers=head_req)

#build pyquery object from response-content
page = pq(r.content)

#get page title
title = page.find('title')
print title.html()

#get page keyword
kw = page.find('meta[name="keywords"]')
print kw.attr('content')
分类: Python, 开发 标签: ,

阿里云OSS python sdk使用简介

2017年9月20日 没有评论

阿里云OSS可以方便的存储各类数据,配合CDN的使用,能够极大提高数据的访问效率。向OSS存放数据时一般要登陆阿里云,再进入OSS管理控制台,选择bucket上传文件。手动操作步骤还是有点繁琐的。好在阿里为我们提供了api和sdk,能够实现自动化操作。

这里简单介绍一下阿里云OSS-Python-SDK的使用方法。

  1. 安装:pip install oss2
  2. 检查:在Python命令行中输入import oss2;oss2.__version__。安装成功则会显示版本号
  3. 在OSS管理控制台中创建AccessKey
    1. 进入OSS控制管理台首页,点右上侧的AccessKey按钮,打开AccessKey管理控制台
    2. 点击提示框中的“开始使用子用户AccessKey”–>设置用户名–>设置权限,仅选择AliyunOSSFullAccess即可–>开始创建用户–>验证手机号后就创建成功了
    3. 在“访问控制台RAM”页面的“用户管理”中可看到刚才创建的用户,点击用户名
    4. 在“用户详情”页的下边能看到“用户AccessKey”,默认已生成了一个AccessKey
    5. 我们可以随时点右侧的“创建AccessKey”来生成新的AccessKey,创建成功会显示AccessKeyID和AccessKeySecret。这两个参数是通过SDK访问OSS必需的。
  4. SDK的使用,可参考官方手册快速入门,也可以通过官方提供的示例进行测试。下边的代码演示了如何上传一个文档对象到OSS。
    # -*- coding: utf-8 -*-
    import os
    import shutil
    
    import oss2
    
    # 首先初始化AccessKeyId、AccessKeySecret、Endpoint等信息。
    # 把诸如“<你的AccessKeyId>”替换成真实的AccessKeyId等。
    #
    # 以上海区域为例,Endpoint可以是:
    # http://oss-cn-shanghai.aliyuncs.com
    # https://oss-cn-shanghai.aliyuncs.com
    # 分别以HTTP、HTTPS协议访问。
    access_key_id = os.getenv('OSS_TEST_ACCESS_KEY_ID', 'LTdsa52Gjv0Nt6')
    access_key_secret = os.getenv('OSS_TEST_ACCESS_KEY_SECRET', 'dijw14JxbYeeKdaght3DG4w0k96KQBHu')
    bucket_name = os.getenv('OSS_TEST_BUCKET', 'my-bucket')
    endpoint = os.getenv('OSS_TEST_ENDPOINT', 'oss-cn-shanghai.aliyuncs.com')
    
    # 确认上面的参数都填写正确了
    for param in (access_key_id, access_key_secret, bucket_name, endpoint):
        assert '<' not in param, '请设置参数:' + param
    
    # 创建Bucket对象,所有Object相关的接口都可以通过Bucket对象来进行
    bucket = oss2.Bucket(oss2.Auth(access_key_id, access_key_secret), endpoint, bucket_name)
    
    # 上传文件 “本地座右铭.txt” 到OSS,并命名为 “云上座右铭.txt”
    with open(oss2.to_unicode('本地座右铭.txt'), 'rb') as f:
        bucket.put_object('云上座右铭.txt', f)
分类: Python, 开发 标签: , , ,

Httpry:简明http抓包工具

2017年7月27日 没有评论

tcpdump是流量分析时最常用的抓包工具,功能很强大。抓取http get交互消息的常用命令是:

tcpdump -XvvennSs 0 -i eth0 tcp[20:2]=0x4745 or tcp[20:2]=0x4854 -w eth0-http.pcap

通常我们会把抓取的http包保存成文件,然后用wireshark打开分析。

有时候,我们不需要对流量观察得特别深入,仅仅是看一下有什么样的流量,不需要存盘分析。

使用tcpdump的话输出内容不直观,比如wget http://www.baidu.com/的输出如下:

15:05:27.837705 00:16:3e:04:af:53 > ee:ff:ff:ff:ff:ff, ethertype IPv4 (0x0800), length 165: (tos 0x0, ttl 64, id 18764, offset 0, flags [DF], proto TCP (6), length 151)
139.129.205.48.53353 > 220.181.112.244.80: Flags [P.], cksum 0xa6e5 (incorrect -> 0xe0b0), seq 2930938556:2930938667, ack 65362085, win 115, length 111
0x0000: 4500 0097 494c 4000 4006 4ab9 8b81 cd30 E…IL@.@.J….0
0x0010: dcb5 70f4 d069 0050 aeb2 92bc 03e5 58a5 ..p..i.P……X.
0x0020: 5018 0073 a6e5 0000 4745 5420 2f20 4854 P..s….GET./.HT
0x0030: 5450 2f31 2e30 0d0a 5573 6572 2d41 6765 TP/1.0..User-Age
0x0040: 6e74 3a20 5767 6574 2f31 2e31 3220 286c nt:.Wget/1.12.(l
0x0050: 696e 7578 2d67 6e75 290d 0a41 6363 6570 inux-gnu)..Accep
0x0060: 743a 202a 2f2a 0d0a 486f 7374 3a20 7777 t:.*/*..Host:.ww
0x0070: 772e 6261 6964 752e 636f 6d0d 0a43 6f6e w.baidu.com..Con
0x0080: 6e65 6374 696f 6e3a 204b 6565 702d 416c nection:.Keep-Al
0x0090: 6976 650d 0a0d 0a ive….
15:05:27.860678 ee:ff:ff:ff:ff:ff > 00:16:3e:04:af:53, ethertype IPv4 (0x0800), length 449: (tos 0x60, ttl 48, id 47418, offset 0, flags [DF], proto TCP (6), length 435)
220.181.112.244.80 > 139.129.205.48.53353: Flags [P.], cksum 0x6a94 (correct), seq 65362085:65362480, ack 2930938667, win 772, length 395
0x0000: 4560 01b3 b93a 4000 3006 e94e dcb5 70f4 E`…:@.0..N..p.
0x0010: 8b81 cd30 0050 d069 03e5 58a5 aeb2 932b …0.P.i..X….+
0x0020: 5018 0304 6a94 0000 4854 5450 2f31 2e31 P…j…HTTP/1.1
0x0030: 2032 3030 204f 4b0d 0a53 6572 7665 723a .200.OK..Server:
0x0040: 2062 6665 2f31 2e30 2e38 2e31 380d 0a44 .bfe/1.0.8.18..D
0x0050: 6174 653a 2054 6875 2c20 3237 204a 756c ate:.Thu,.27.Jul
0x0060: 2032 3031 3720 3037 3a30 353a 3237 2047 .2017.07:05:27.G
0x0070: 4d54 0d0a 436f 6e74 656e 742d 5479 7065 MT..Content-Type
0x0080: 3a20 7465 7874 2f68 746d 6c0d 0a43 6f6e :.text/html..Con
0x0090: 7465 6e74 2d4c 656e 6774 683a 2032 3338 tent-Length:.238

此时,httpry是一个很好的替代工具。使用httpry捕获上述请求,输出如下:

2017-07-27 15:08:50 139.129.205.48 220.181.112.244 > GET www.baidu.com / HTTP/1.0 – –
2017-07-27 15:08:50 220.181.112.244 139.129.205.48 < – – – HTTP/1.1 200 OK

简单明了。

  • 安装
    • 下载源码,make && make install就ok了
    • 这个程序依赖libpcap-devel库,没有的话就yum install -y libpcap-devel
  • 使用
    • 最简单的:httpry -i eth0
    • 支持过滤http请求方法:httpry -i eth0 -m GET
    • 支持保存抓包:httpry -i eth0 -o eth0-http.log
    • 可以指定packet filter:httpry -i eth0 ‘dst host www.baidu.com’
分类: 工具 标签: , , ,

一个从MongoDB中导出给定日期范围内数据的shell脚本

2017年6月29日 没有评论

前几天介绍了使用mongoexport的使用方法,结合date命令的使用,这里给出一个完整的脚本,用来从MongoDB中导出某个日期范围内的数据,数据导出后从MongoDB中进行删除

#!/bin/sh
#d1, the beginning date, eg:2017-06-28
d1=$1 
d1=`date -d $d1 +%F`
 
#transfer d1 to seconds
d2=`date -d $d1 +%s`
#increase d1 by one day
d2=`expr $d2 + 86400`
#transfer d2 from seconds to day
d2=`date -d @$d2 +%F`

#build query json
qj='{"time":{$gte:ISODate("'"$d1"'T00:00:00Z")}, "time":{$lt:ISODate("'"$d2"'T00:00:00Z")}}'
#export
./mongoexport --db testDB --collection testColl --query="$qj" --fields="userId,userName" --type="csv" --out results"-$d1" --noHeaderLine

#generate js for delete
echo 'var db = connect("testDB");' > delete.js
echo 'db.testColl.remove({"time":{$gte:ISODate("'"$d1"'T00:00:00Z")}, "time":{$lt:ISODate("'"$d2"'T00:00:00Z")}})' >> delete.js
#delete 
./mongo delete.js

备注:如果MongoDB使用的不是默认端口27017,上面的脚本里mongoexport和mongo都需要增加–port参数,并且delete.js中的connect方法也需要指定端口,指定方式为:

var db = connect("127.0.0.1:port/testDB");
分类: MongoDB, Shell 标签: ,

shell中计算偏移日期的方法

2017年6月29日 没有评论

给定一个日期,如何在shell中计算前几天或者后几天的日期?

方法如下:

#给定当前日期
d1=`date +%F`

#计算两天后的日期
offset=2

 #d1转换成秒, since 1970-01-01 00:00:00 UTC
d1s=`date -d $d1 +%s`

#将偏移天数换算成秒数
offset_s=`expr 86400 \* $offset` 

#计算偏移后 的秒数
d2s=`expr $d1s + $offset_s`

#将偏移后的秒数转换成日期
d2=`date -d @$d2s + %F`

主要原理就是通过date -d +%s来实现日期和秒之间的互转,详情man date一下吧。

分类: Shell 标签: ,