工作,学习,生活,这里将会有一些记录. 备用域名:http://meisw.wdlinux.cn 注册 | 登陆
浏览模式: 标准 | 列表全部文章

Redigo--用池管理redis连接

在golang的项目中,若要频繁的用redis(或者其他类似的NoSQL)来存取数据,最好用redigo自带的池来管理连接。

 

不然的话,每当要操作redis时,建立连接,用完后再关闭,会导致大量的连接处于TIME_WAIT状态(redis连接本质上就是tcp)。

 

注:TIME_WAIT,也叫TCP半连接状态,会继续占用本地端口。

 

以下为redis连接池的golang实现:

 

 

import (

"github.com/garyburd/redigo/redis"

"github.com/astaxie/beego"

"time"

)

 

var (

// 定义常量

RedisClient     *redis.Pool

REDIS_HOST string

REDIS_DB   int

)

 

func init() {

// 从配置文件获取redis的ip以及db

REDIS_HOST = beego.AppConfig.String("redis.host")

REDIS_DB, _ = beego.AppConfig.Int("redis.db")

// 建立连接池

RedisClient = &redis.Pool{

// 从配置文件获取maxidle以及maxactive,取不到则用后面的默认值

MaxIdle:     beego.AppConfig.DefaultInt("redis.maxidle", 1),

MaxActive:   beego.AppConfig.DefaultInt("redis.maxactive", 10),

IdleTimeout: 180 * time.Second,

Dial: func() (redis.Conn, error) {

c, err := redis.Dial("tcp", REDIS_HOST)

if err != nil {

return nil, err

}

// 选择db

c.Do("SELECT", REDIS_DB)

return c, nil

},

}

}

其中,各参数的解释如下:

MaxIdle:最大的空闲连接数,表示即使没有redis连接时依然可以保持N个空闲的连接,而不被清除,随时处于待命状态。

 

MaxActive:最大的激活连接数,表示同时最多有N个连接

 

IdleTimeout:最大的空闲连接等待时间,超过此时间后,空闲连接将被关闭

 

Dial:建立连接

 

使用连接池时的代码:

 

 

// 从池里获取连接

rc := RedisClient.Get()

// 用完后将连接放回连接池

defer rc.Close()

以上就是连接池的用法了,很简单吧。

GraphicsMagick为图片添加水印

GraphicsMagick号称图像处理领域的瑞士军刀。提供了健壮及高效的图像处理工具包和库,支持超过88种主流图片格式包括:BMP,GIF,JPEG,JPEG-2000,PNG,PDF,PNM,TIFF,DPX…

现在最新稳定版本为:1.3.12。安装之前,因为是图片处理,所以需要系统中安装了libpng和libjpeg的开发包,否则的话不会安装这两种文件的支持。

官方下载地址:http://www.graphicsmagick.org/<br><br><br>http://www.imagemagick.org/download/<br><br><br>

 

命令格式:gm convert [ options ... ] input_file output_file

 

下面给出一些常用玩法,本文也将陆续添加其他玩法,敬请关注!

 

重定义尺寸,取样质量

 

gm convert -quality 80 -resize 100×100 input.jpg output.jpg

加文字水印,指定字体、字体大小、颜色、位置

 

gm convert -font ArialBold -pointsize 45 -fill red -draw “text 100,100 www.saysth.com” input.jpg output.jpg

加图片水印至右下角,透明度50%

 

gm composite -gravity southeast -dissolve 50 watermark.png input.jpg output.jpg

加图片水印至制定位置,透明度50%

 

 gm composite -geometry +50+50 -dissolve 50 watermark.png input.jpg output.jpg<br><br><br>http://www.imagemagick.org/download/

 

golang time 时间的加减法

 time包中的Add和Sub的用法,Add用于计算某个时间之前和之后的时间点,Sub用于计算两个时间差

package main


import (

"fmt"

"strings"

"time"

)


func main() {

// Add 时间相加

now := time.Now()

// ParseDuration parses a duration string.

// A duration string is a possibly signed sequence of decimal numbers,

// each with optional fraction and a unit suffix,

// such as "300ms", "-1.5h" or "2h45m".

//  Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".

// 10分钟前

m, _ := time.ParseDuration("-1m")

m1 := now.Add(m)

fmt.Println(m1)


// 8个小时前

h, _ := time.ParseDuration("-1h")

h1 := now.Add(8 * h)

fmt.Println(h1)


// 一天前

d, _ := time.ParseDuration("-24h")

d1 := now.Add(d)

fmt.Println(d1)


printSplit(50)


// 10分钟后

mm, _ := time.ParseDuration("1m")

mm1 := now.Add(mm)

fmt.Println(mm1)


// 8小时后

hh, _ := time.ParseDuration("1h")

hh1 := now.Add(hh)

fmt.Println(hh1)


// 一天后

dd, _ := time.ParseDuration("24h")

dd1 := now.Add(dd)

fmt.Println(dd1)


printSplit(50)


// Sub 计算两个时间差

subM := now.Sub(m1)

fmt.Println(subM.Minutes(), "分钟")


sumH := now.Sub(h1)

fmt.Println(sumH.Hours(), "小时")


sumD := now.Sub(d1)

fmt.Printf("%v 天\n", sumD.Hours()/24)


}


func printSplit(count int) {

fmt.Println(strings.Repeat("#", count))

}

基于timestamp和nonce的防止重放攻击方案

 以前总是通过timestamp来防止重放攻击,但是这样并不能保证每次请求都是一次性的。今天看到了一篇文章介绍的通过nonce(Number used once)来保证一次有效,感觉两者结合一下,就能达到一个非常好的效果了。

重放攻击是计算机世界黑客常用的攻击方式之一,所谓重放攻击就是攻击者发送一个目的主机已接收过的包,来达到欺骗系统的目的,主要用于身份认证过程。

首先要明确一个事情,重放攻击是二次请求,黑客通过抓包获取到了请求的HTTP报文,然后黑客自己编写了一个类似的HTTP请求,发送给服务器。也就是说服务器处理了两个请求,先处理了正常的HTTP请求,然后又处理了黑客发送的篡改过的HTTP请求。

基于timestamp的方案

每次HTTP请求,都需要加上timestamp参数,然后把timestamp和其他参数一起进行数字签名。因为一次正常的HTTP请求,从发出到达服务器一般都不会超过60s,所以服务器收到HTTP请求之后,首先判断时间戳参数与当前时间相比较,是否超过了60s,如果超过了则认为是非法的请求。

假如黑客通过抓包得到了我们的请求url: 
http://koastal.site/index/Info?uid=ZX07&stime=1480862753&sign=80b886d71449cb33355d017893720666 
其中

$sign=md5($uid.$token.$stime); // 服务器通过uid从数据库中可读出token
  • 1
  • 2

一般情况下,黑客从抓包重放请求耗时远远超过了60s,所以此时请求中的stime参数已经失效了。 
如果黑客修改stime参数为当前的时间戳,则sign参数对应的数字签名就会失效,因为黑客不知道token值,没有办法生成新的数字签名。

但这种方式的漏洞也是显而易见的,如果在60s之后进行重放攻击,那就没办法了,所以这种方式不能保证请求仅一次有效。

基于nonce的方案

nonce的意思是仅一次有效的随机字符串,要求每次请求时,该参数要保证不同,所以该参数一般与时间戳有关,我们这里为了方便起见,直接使用时间戳的16进制,实际使用时可以加上客户端的ip地址,mac地址等信息做个哈希之后,作为nonce参数。 
我们将每次请求的nonce参数存储到一个“集合”中,可以json格式存储到数据库或缓存中。 
每次处理HTTP请求时,首先判断该请求的nonce参数是否在该“集合”中,如果存在则认为是非法请求。

假如黑客通过抓包得到了我们的请求url: 
http://koastal.site/index/Info?uid=ZX07&nonce=58442c21&sign=80b886d71449cb33355d017893720666

其中

$sign=md5($uid.$token.$nonce); // 服务器通过uid从数据库中可读出token
  • 1
  • 2

nonce参数在首次请求时,已经被存储到了服务器上的“集合”中,再次发送请求会被识别并拒绝。 
nonce参数作为数字签名的一部分,是无法篡改的,因为黑客不清楚token,所以不能生成新的sign。

这种方式也有很大的问题,那就是存储nonce参数的“集合”会越来越大,验证nonce是否存在“集合”中的耗时会越来越长。我们不能让nonce“集合”无限大,所以需要定期清理该“集合”,但是一旦该“集合”被清理,我们就无法验证被清理了的nonce参数了。也就是说,假设该“集合”平均1天清理一次的话,我们抓取到的该url,虽然当时无法进行重放攻击,但是我们还是可以每隔一天进行一次重放攻击的。而且存储24小时内,所有请求的“nonce”参数,也是一笔不小的开销。

基于timestamp和nonce的方案

那我们如果同时使用timestamp和nonce参数呢? 
nonce的一次性可以解决timestamp参数60s的问题,timestamp可以解决nonce参数“集合”越来越大的问题。

我们在timestamp方案的基础上,加上nonce参数,因为timstamp参数对于超过60s的请求,都认为非法请求,所以我们只需要存储60s的nonce参数的“集合”即可。

假如黑客通过抓包得到了我们的请求url: 
http://koastal.site/index/Info?uid=ZX07&stime=1480862753&nonce=58442c21&sign=80b886d71449cb33355d017893720666

其中

$sign=md5($uid.$token.$stime.$nonce); // 服务器通过uid从数据库中可读出token
  • 1
  • 2

如果在60s内,重放该HTTP请求,因为nonce参数已经在首次请求的时候被记录在服务器的nonce参数“集合”中,所以会被判断为非法请求。超过60s之后,stime参数就会失效,此时因为黑客不清楚token的值,所以无法重新生成签名。

综上,我们认为一次正常的HTTP请求发送不会超过60s,在60s之内的重放攻击可以由nonce参数保证,超过60s的重放攻击可以由stime参数保证。

因为nonce参数只会在60s之内起作用,所以只需要保存60s之内的nonce参数即可。

我们并不一定要每个60s去清理该nonce参数的集合,只需要在新的nonce到来时,判断nonce集合最后一次修改时间,超过60s的话,就清空该集合,存放新的nonce参数集合。其实nonce参数集合可以存放的时间更久一些,但是最少是60s。

验证流程

//判断stime参数是否有效 if( $now - $stime > 60){     die("请求超时"); } //判断nonce参数是否在“集合”已存在 if( in_array($nonce,$nonceArray) ){     die("请求仅一次有效"); } //验证数字签名     if ( $sign != md5($uid.$token.$stime.$nonce) ){     die("数字签名验证失败"); } //判断是否需要清理nonce集合 if( $now - $nonceArray->lastModifyTime > 60 ){     $nonceArray = null; } //记录本次请求的nonce参数 $nonceArray.push($nonce);   //开始处理合法的请求

ubuntu怎样让vim记住文件上次打开的位置

 进到/etc/vim/vimrc 使用root,添加

au BufReadPost * if line("'\"") > 0|if line("'\"") <= line("$")|exe("norm '\"")|else|exe "norm $"|endif|endif
即可

JSON-RPC好,还是RESTful API好?

 作者:Vincross

链接:https://www.zhihu.com/question/28570307/answer/163638731
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

两者没有高下之分,无非是一种约定俗成的标准。习惯用RPC就用RPC,能理解REST就用REST。

JSON-RPC比较符合直观,格式也相对宽松;

REST最近正流行,有自己的一套设计规范。


REST面对的疑问跟当年刚开始流行面向对象时的情况是一样的。

它适合很多情况,但并不适合所有情况。

最差的结果就是盲目跟风,又对REST的概念和理念一知半解,最后搞出一个半吊子的怪胎,还自我标榜用了流行的RESTful API。


REST是一种设计风格,它的很多思维方式与RPC是完全冲突的。

RPC的思想是把本地函数映射到API,也就是说一个API对应的是一个function,我本地有一个getAllUsers,远程也能通过某种约定的协议来调用这个getAllUsers。至于这个协议是Socket、是HTTP还是别的什么并不重要;

RPC中的主体都是动作,是个动词,表示我要做什么。

而REST则不然,它的URL主体是资源,是个名词。而且也仅支持HTTP协议,规定了使用HTTP Method表达本次要做的动作,类型一般也不超过那四五种。这些动作表达了对资源仅有的几种转化方式。


这种设计思路是反程序员直觉的,因为在本地业务代码中仍然是一个个的函数,是动作,但表现在接口形式上则完全是资源的形式。

就像面向对象的「万物皆对象」理论在习惯了纯粹面向过程开发的程序员眼里显得十分别扭一样:我的代码本来就是按顺序、循环、分支这么运行的啊,为啥非得在很明确的结构上封装一层一层的基类子类接口,还要故意给两个函数起同一个名字,调用时才选择用哪一个呢?


使用「万物皆资源」的思想编写实际项目中的API接口时,最常见的问题就是「这玩意到底是个什么资源?………………算了,我就直接写吧,不管什么风格了」

  • 比如,login和logout应该怎么REST化?
  • 比如,多条件复合搜索在GET里写不下怎么办?
  • 比如,大量资源的删除难道要写几千个DELETE?

其实在理解了REST后,这些都不是什么无解的难题,只是思维方式要转换一下:

  • login和logout其实只是对session资源的创建和删除;
  • search本身就是个资源,使用POST创建,如果不需持久化,可以直接在Response中返回结果,如果需要(如翻页、长期缓存等),直接保存搜索结果并303跳转到资源地址就行了;
  • id多到连url都写不下的请求,应该创建task,用GET返回task状态甚至执行进度;

……等等等。


如果只是规定了一种规范,却不理解它表相下面的思维方式,实施中又按照自己的理解随意变动,那结果肯定是混乱不堪的。

当然,API怎么写是开发者的自由。但如果一个API在url里放一堆动词、资源设计混乱、各种乱用HTTP Method和Status Code,还自称RESTful API的话,那就像你养了一条狗,还管它叫猫一样。

这种混搭产物,不如叫它REFU吧。

(Remove Extension From Url:从url里去掉文件扩展名)


前面说了半天REST的理念和不懂REST造成的问题,但是,这并不代表REST比RPC更「高等」,更不是说不理解REST的人是落伍的。

所谓代码风格、接口形式、各种林林总总的格式规定,其实都是为了在团队内部形成共识、防止个人习惯差异引起的混乱。JSON-RPC当然也是有规范的,但相比REST实在宽松太多了。

如果一个开发团队规定必须在url里写action,所有请求都是POST,可以吗?当然也没问题,只是不要拿出去标榜自己写的是RESTful API就行。

规范最终还是为了开发者和软件产品服务的,如果它能带来便利、减少混乱,就值得用;反之,如果带来的麻烦比解决的还多,那就犯不上纯粹跟风追流行了。

 

https://www.zhihu.com/question/28570307 

为什么需要RPC,而不是简单的HTTP接口

 转载自:http://www.oschina.net/question/271044_2155059?sort=default&p=1#answers

目前有很多Java的RPC框架,有基于Json的,有基于XML,也有基于二进制对象的。

论复杂度,RPC框架肯定是高于简单的HTTP接口的。但毋庸置疑,HTTP接口由于受限于HTTP协议,需要带HTTP请求头,导致传输起来效率或者说安全性不如RPC。

现在问题是,遇到怎样的瓶颈了才需要或者说更适合用RPC(比如像阿里这么大的请求并发量,简单的HTTP肯定达不到预期),但问题是大家所在的公司,要有像阿里这么大的量是比较少的,甚至说1/1000的量可能都没有,那我们还需要使用RPC吗?

技术应该不是为了使用新技术而去使用,而应该是旧技术存在某些瓶颈,存在难以支撑或者扩展性越老越差等问题暴露出来之后,用新技术来进行解决。

那RPC最大的优点,或者说它相比简单的HTTP接口,它的优势、更适合它的业务场景是怎样呢?简单的HTTP又哪里不足,哪些场景明显不太适合呢?

---

RPC=Remote Produce Call 是一种技术的概念名词. HTTP是一种协议,RPC可以通过HTTP来实现,也可以通过Socket自己实现一套协议来实现.所以楼主可以换一个问法,为何RPC还有除HTTP 之外的实现法,有何必要.毕竟除了HTTP实现外,私有协议不具备通用性.那么我想唯一的答案就在于HTTP不能满足其业务场景的地方,所以这个就要具体 案例具体分析了.

------

http接口是在接口不多、系统与系统交互较少的情况下,解决信息孤岛初期常使用的一种通信手段;优点就是简单、直接、开发方便。利用现成的http协议 进行传输。但是如果是一个大型的网站,内部子系统较多、接口非常多的情况下,RPC框架的好处就显示出来了,首先就是长链接,不必每次通信都要像http 一样去3次握手什么的,减少了网络开销;其次就是RPC框架一般都有注册中心,有丰富的监控管理;发布、下线接口、动态扩展等,对调用方来说是无感知、统 一化的操作。第三个来说就是安全性。最后就是最近流行的服务化架构、服务化治理,RPC框架是一个强力的支撑

---

rpc是一种概念,http也是rpc实现的一种方式。论复杂度,dubbo/hessian用起来是超级简单的。最近用dubbo和hessian比较多,http的几乎都被废弃了。

至于为什么用,其实很简单,业务场景不一样。我最早的单位所有的代码都在一个工程里,一次要发布几百m的代码。这种架构是非常有利于小程序的。但是我们为什么要应用rpc层呢,一个功能,一套代码下来不就解决了么?我觉得有几个好处:

1 灵活部署 2 解耦 至于为什么,当你用到的时候,你会体会。

系统做大了,肯定是需要做微服务的。 现在我们做电商就是这样,单独有一个订单系统,支付系统,商品系统,用户系统。都是分开部署,单独上线的。 但我们交互是用HTTP接口来交互的,我想转用RPC,但问题是我现在还没发现为什么需要用RPC,我还没能理解它的作用和意义

用http交互其实就已经属于rpc了

---------

RPC:远程过程调用。RPC的核心并不在于使用什么协议。RPC的目的是让你在本地调用远程的方法,而对你来说这个调用是透明的,你并不知道这个调用的方法是部署哪里。通过RPC能解耦服务,这才是使用RPC的真正目的。RPC的原理主要用到了动态代理模式,至于http协议,只是传输协议而已。简单的实现可以参考spring remoting,复杂的实现可以参考dubbo。

--------

RPC是一个软件结构概念,是构建分布式应用的理论基础。就好比为啥你家可以用到发电厂发出来的电?是因为电是可以传输的。至于用铜线还是用铁丝还是其他 种类的导线,也就是用http还是用其他协议的问题了。这个要看什么场景,对性能要求怎么样。比如在java中的最基本的就是RMI技术,它是java原 生的应用层分布式技术。我们可以肯定的是在传输性能方面,RMI的性能是优于HTTP的。那为啥很少用到这个技术?那是因为用这个有很多局限性,首先它要 保证传输的两端都要要用java实现,且两边需要有相同的对象类型和代理接口,不需要容器,但是加大了编程的难度,在应用内部的各个子系统之间还是会看到 他的身影,比如EJB就是基于rmi技术的。这就与目前的bs架构的软件大相径庭。用http必须要服务端位于http容器里面,这样减少了网络传输方面 的开发,只需要关注业务开发即可。所以在架构一个软件的时候,不能一定根据需求选定技术。

git使用说明

 git reset --hard HEAD^^

 
git checkout -b v3
 
git branch origin/master
 
 
.gitconfig 文件中添加
 
[credential]
    helper = store
 
git config credential.helper 'cache –timeout=3600'
git config –global credential.helper store
 
 
git remote -v
 
 
git init
 
git remote add origin https://gitee.com/wdlinux/lanmp.git
 
把本地库的内容推送到远程,使用 git push命令,实际上是把当前分支master推送到远程。
 
由于远程库是空的,我们第一次推送master分支时,加上了 –u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。推送成功后,可以立刻在github页面中看到远程库的内容已经和本地一模一样了,上面的要输入github的用户名和密码如下所示:
 
 
git checkout 命令加上 –b参数表示创建并切换,相当于如下2条命令
git branch dev
git checkout dev
git branch查看分支,会列出所有的分支,当前分支前面会添加一个星号。
 
 
现在我们可以把dev分支上的内容合并到分支master上了,可以在master分支上,使用如下命令 git merge dev 如下所示:
 
 
总结创建与合并分支命令如下:
   查看分支:git branch
   创建分支:git branch name
   切换分支:git checkout name
创建+切换分支:git checkout –b name
合并某分支到当前分支:git merge name
删除分支:git branch –d name
 
 
3.分支管理策略。
      通常合并分支时,git一般使用”Fast forward”模式,在这种模式下,删除分支后,会丢掉分支信息,现在我们来使用带参数 –no-ff来禁用”Fast forward”模式。首先我们来做demo演示下:
 
创建一个dev分支。
修改readme.txt内容。
添加到暂存区。
切换回主分支(master)。
合并dev分支,使用命令 git merge –no-ff  -m “注释” dev
查看历史记录
 
 
Git基本常用命令如下:
   mkdir:         XX (创建一个空目录 XX指目录名)
   pwd:          显示当前目录的路径。
   git init          把当前的目录变成可以管理的git仓库,生成隐藏.git文件。
   git add XX       把xx文件添加到暂存区去。
   git commit –m “XX”  提交文件 –m 后面的是注释。
   git status        查看仓库状态
   git diff  XX      查看XX文件修改了那些内容
   git log          查看历史记录
   git reset  –hard HEAD^ 或者 git reset  –hard HEAD~ 回退到上一个版本
                        (如果想回退到100个版本,使用git reset –hard HEAD~100 )
   cat XX         查看XX文件内容
   git reflog       查看历史记录的版本号id
   git checkout — XX  把XX文件在工作区的修改全部撤销。
   git rm XX          删除XX文件
   git remote add origin https://github.com/tugenhua0707/testgit 关联一个远程库
   git push –u(第一次要用-u 以后不需要) origin master 把当前master分支推送到远程库
   git clone https://github.com/tugenhua0707/testgit  从远程库中克隆
   git checkout –b dev  创建dev分支 并切换到dev分支上
   git branch  查看当前所有的分支
   git checkout master 切换回master分支
   git merge dev    在当前的分支上合并dev分支
   git branch –d dev 删除dev分支
   git branch name  创建分支
   git stash 把当前的工作隐藏起来 等以后恢复现场后继续工作
   git stash list 查看所有被隐藏的文件列表
   git stash apply 恢复被隐藏的文件,但是内容不删除
   git stash drop 删除文件
   git stash pop 恢复文件的同时 也删除文件
   git remote 查看远程库的信息
   git remote –v 查看远程库的详细信息
   git push origin master  Git会把master分支推送到远程库对应的远程分支上
 
http://blog.jobbole.com/78960/