枝连效应小谈

      今天来公司时看到地铁站里红烧牛肉面的广告, 突发奇想: 广告行业为什么不枝连在一起来宣传? 比如卖汽车的,一般会有一个长得很帅的男模,这时为什么不顺便做服装的生意。一般情况下一个广告(3分钟以内),确实很难让人记住一大推的品牌,但是只有一个也会很无聊, 我想1-3分钟来熟悉3个品牌是很好的, 这三个产品(当然没有竞争关系,而且会有一些相似之处,比如用户品味、依赖关系等)可以一起投资来做一个效果很不错的广告,而且用户也会感觉很亲切,因为团结和结合的东西一般都会很亲民。所以,广告行业也需要打破公司间的壁垒,携手走向共赢。

关键字: 枝连、共赢、广告

udp包长度问题追踪

因为日常开发中我的应用日志一般都是通过udp包在网络上传输的,这样的话,当包长大于一定长度就会报错:

Traceback (most recent call last):
  File "test.py", line 8, in <module>
    sock.sendto(msg, ("127.0.0.1", 5555))
socket.error: [Errno 40] Message too long

测试下来发现,发送内容大于等于8185时就会报错,8184是个最大的安全值。测试程序如下:

client:

# coding=utf-8
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
msg = ""
for i in xrange(0, 1000):
  #msg += "中国你好啊,"
  msg += "hello,"
msg += "\n"
sock.sendto(msg, ("127.0.0.1", 5555))

server 端监听:

nc -ul 127.0.0.1 5555

发现这个现象后从网上找原因,首先是了解到 MTU(Maximum Transmission Unit,最大传输单元)。这个值一般设置都是1500 bytes. 可以通过ipconfig 或是 netstat -i 来查看各个网卡这个值的设置情况。然后去掉IP数据报的首部为20字节,UDP数据报的首部8字节,剩余1472字节用来存储数据。我们可以通过ping(ICMP协议,和UDP一样,报头也占用8个字节)来断定实际包传输情况。

找一个server机(IP 172.19.44.10):

root@jrtool ~]# netstat -i
Kernel Interface table
Iface       MTU Met    RX-OK RX-ERR RX-DRP RX-OVR    TX-OK TX-ERR TX-DRP TX-OVR Flg
eth0       1500   0 605731701      0      0      0 663673344      0      0      0 BMRU
lo        16436   0   614404      0      0      0   614404      0      0      0 LRU

然后在其他机器ping:


在server端:

可见本机发UDP包,最大可可发 65507 bytes (udp 理论长度 2^16 – udp head – iphead 也就是 65535-28=65507), 夸机器发包, 会比MTU(1500 大一些),可以达到 8184 ( 2^13 – 8 ). 

结论:

1. udp包最好不要超过1480 (IP 要占去20 bytes)

2. Internet上的标准MTU值为576字节,所以我建议在进行Internet的UDP编程时.    最好将UDP的数据长度控件在548字节(576-8-20)以内

3. udp包长在1500 到 65535 bytes 之间时,一般也可以接收,和发送的buffer设置有关,也和平台有关。

4. udp日志的设置最大就为8184 即可。

5. 系统的MTU是可以设置的,方法是: sudo ifconfig eth0 mtu 5000

 

参考: http://stackoverflow.com/questions/11809727/sendto-returns-values-greater-than-mtu-on-sock-dgram-udp-socket  

应用日志压缩与python字符问题小结

    年末了,事情不太多, 就规划着将开发的基层服务完善下。在生产环境查看问题时,如果日志不够完善,将会花费较多时间,所以一定要有一个靠谱的日志系统。本次日志系统主要会收集应用的数据交互情况, 包括db操作、redis操作、API操作等,因为日志量比较大,所以一定要将日志尽量的压缩。比如保存python字符串时中文字符的长度就会小一些, ( 试试 len("中文") == 6   , len(u"中文") == 2 ) 在进行服务器日志压缩过程中,发现从db中取出的字段内容都是 "\u559c\u6b22\u4e00\u4e2a\u4eba" , 这样会有两个问题:

1. 中文不直接显示,后期查看时需要再转一下;

2. 存放时多占用了多个字符, \u559c 就当做了6个字符来存放了。 

然后就开始了转码之旅:

因为"\u559c\u6b22\u4e00\u4e2a\u4eba" 这样的字符本身已经是 escape序列了,那么什么叫做escape序列的字符串呢, 简单来说就是为了保存string到db等地方, python自动为这个string中除了字母和数字以外的字符,都加上一个反斜线, 比如在re模块中

>>> print re.escape('test_@#$')
test\_\@\#\$

  所以,对于这个已经是escape序列的unicode,我们只需要反转一下,然后正常显示即可:

首先,先来个粗暴的 ,因为json 的dumps 方法自带是个escape序列的转换参数,我们先使用json来转换一下,再反转一下:

result = json.dumps(json.loads(result), ensure_ascii=False) 


可以正常显示中文了。 查看 ensure_ascii=False 这个参数,主要是引入了 escape 序列转换。

然后, 来一个优雅一点的:

result = result.decode('unicode_escape')  # 此处使用raw_unicode_escape效果是一样的

最后,来个简洁的, 其实我们直接转换这个unicode编码的字符串就行了,

 result = eval("u'" + result + "'")

至此,问题已经解决。

然后我们就来复习一下unicode 编码和解码的知识点:


# python 2.x str 转 unicode: 
str_string.decode('original_encoding')
# s.decode 将s解码成unicode,参数指定的是s本来的编码方式。这个和unicode(s,encodename)是一样的。

# unicode 转 str:
unicode_string.encode('target_encoding')
​# u.encode 将unicode编码成str对象,参数指定使用的编码方式

 

标准编码

编码                                                      描述
utf-8                                    变量长度为8 的编码(默认编码)
utf-16                                  变量长度为16 的编码(大/小端)
utf-16-le                             小端UTF-16 编码
utf-16-be                           大端UTF-16 编码
ascii 7-bit                          7 位ASCII 码表
iso-8859-1                        ISO 8859-1 (Latin-1) 码表
unicode-escape              (定义见Python Unicode 构造函数)
raw-unicode-escape      (定义见Python Unicode 构造函数)
native                                 Python 用的内部格式

ES6 新特性1 — 箭头函数

今天无意看到一种新的方法定义方式,感觉还挺好玩的。记录如下:
 

var sum = (x, y)  =>  x + y;
sum(1,2)  //  result is 3

其中箭头方法是es6 引入的新的方法。 看到这个片段还是在看一个node的优秀项目介绍时看评论见到的(原文在 http://www.csdn.net/article/2013-12-17/2817827)。 感觉箭头方法在表示lambda时还挺方便的。就记录下使用中的一些技巧:

英文地址: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

基本语法如下: (示例部分参考 http://www.cnblogs.com/snandy/p/4403111.html

//基本语法为 (变量列表) => { 语句 }  |  表达式:
(param1, param2, paramN) => { statements }
(param1, param2, paramN) => expression
   // 等同于: => { return expression; }

// 单变量时括号可省略
singleParam => { statements }
singleParam => expression

// 没有参数时需要加上括号:
() => { statements }

// 高级用法:
//返回一个方法:
params => ({foo: bar})

// 支持不定变量的表达方式
(param1, param2, ...rest) => { statements }

//返回对象时需要用小括号包起来(大括号被占用解释为代码块)
var getHash = arr => {
    // ...
    return ({
        name: 'test',
        age: 33
    })
}

//直接作为事件handler
document.addEventListener('click', ev=> {
    console.log(ev)
})

//数组排序(实现cmp函数)
var arr = [1, 9 , 2, 4, 3, 8].sort((a, b)=> {
    if (a - b &gt; 0 ) {
        return 1
    } else {
        return -1
    }
})
arr // [1, 2, 3, 4, 8, 9]

//数组排序复习
function sortAsc(a,b)
{
return a - b;
}
function sortDesc(a,b)
{
return b - a;
}
var arr = new Array(6)
arr[0] = "10"
arr[1] = "5"
arr[2] = "40"
arr[3] = "25"
arr[4] = "1000"
arr[5] = "1"
arr.sort(sortAsc) // ["1", "5", "10", "25", "40", "1000"]
arr.sort(sortDesc) // ["1000", "40", "25", "10", "5", "1"]

//typeof运算符和普通的function一样
var func = a => a
console.log(typeof func); // "function"

// instanceof也返回true,表明也是Function的实例
console.log(func instanceof Function); // true

//箭头函数不能用new
var Person = (name, age) =>  {
    this.name = name
    this.age = age
}
var p = new Func('John', 33) // error

 

这个语法对方法简写和方法内的this带了了影响:

方法简写:

var a = [
  "Hydrogen",
  "Helium",
  "Lithium",
  "Beryl­lium"
];

var a2 = a.map(function(s){ return s.length });

var a3 = a.map( s => s.length );

this语法:

通过箭头方法的使用, 方法可以在内部访问自己的上下文,示例如下:

// to call object's variables
//In ECMAScript 3/5, this issue was fixed by assigning the value in this to a variable that could be closed over
function Person() {
  var self = this; // Some choose `that` instead of `self`. 
                   // Choose one and be consistent.
  self.age = 0;

  setInterval(function growUp() {
    // The callback refers to the `self` variable of which
    // the value is the expected object.
    self.age++;
  }, 1000);
}

// now
function Person(){
  this.age = 0;

  setInterval(() => {
    this.age++; // |this| properly refers to the person object
  }, 1000);
}

var p = new Person();

// strict mode 不受影响:
var f = () => {'use strict'; return this};
f() === window; // or the global object


//调用call 或 apply, 调用只是传参,对整体的this不会有影响

var adder = {
  base : 1,
    
  add : function(a) {
    var f = v => v + this.base;
    return f(a);
  },

  addThruCall: function(a) {
    var f = v => v + this.base;
    var b = {
      base : 2
    };
            
    return f.call(b, a);
  }
};

console.log(adder.add(1));         // This would log to 2
console.log(adder.addThruCall(1)); // This would log to 2 still

 

一些方便的示例:

// An empty arrow function returns undefined
let empty = () => {};

(() => "foobar")() // returns "foobar" 

var simple = a => a > 15 ? 15 : a; 
simple(16); // 15
simple(10); // 10

let max = (a, b) => a > b ? a : b;

// Easy array filtering, mapping, ...

var arr = [5, 6, 13, 0, 1, 18, 23];
var sum = arr.reduce((a, b) => a + b);  // 66
var even = arr.filter(v => v % 2 == 0); // [6, 0, 18]
var double = arr.map(v => v * 2);       // [10, 12, 26, 0, 2, 36, 46]

 

python开发环境备忘 — pip wheel

python以第三方包闻名天下,但是这又为部署带来了巨大的挑战:一般情况下我们是在开发环境进行开发,然后引入了一大堆包,然后往生产环境推时就遇到这这样几个难题:

1. 外部模块版本管理和版本依赖问题,因为过于自由,所以很多时候不同版本之间就是不兼容,这时就需要我们来记录一下各个模块的版本以及他的依赖。

2. 生产环境一般情况下是与外部网络隔绝的,这就使得我们不能随时联网安装或者更新包,这就需要我们将本地的模块打包,然后部署时快速地安装。

这对这些问题,我们就引入了python包管理的内容:常用的有打包为eggs、whl等。 今天就来介绍下打包为whl的情景:

首先我们安装wheel:
 

pip install wheel

以下列出我经常用到的wheel指令:

1. 为一个包创建whl: 

# 打包python-dateutil :
pip wheel --wheel-dir=wheelhouse python-dateutil
pip wheel --wheel-dir=wheelhouse python-dateutil==2.4.2

# 打包python-dateutil 到当前目录下的wheel-dir: 
pip wheel --wheel-dir=wheelhouse python-dateutil   --trusted-host pypi.douban.com

#按照whl列表打包: 
pip wheel --wheel-dir=/local/wheels -r requirements.txt

2. 安装whl: 

pip install python_dateutil.whl

pip install --use-wheel --no-index --find-links=wheelhouse python-dateutil

3. 创建全量的whl列表:

pip freeze > requirements.txt

4. 全量安装whl:

pip install -r requirements.txt

pip install --use-wheel --no-index --find-links=wheelhouse -r requirements.txt

参考官方文档: https://pip.pypa.io/en/stable/user_guide/

 

两列布局高度自适应

在web设计时我们经常会有这样的需求: 顶部和底部是固定的,内容要分左右两列,而左右的内容高度是不固定的。我们还想要左右有不同的背景(或者边框),这时如果左右的高度能保持一样该多好呀(对应了优雅页面设计的“对齐”的哲学原理)。今天就来研究下对齐的好玩的方法:

  1. 当前最常用也最简单的莫过于实用 js 来控制了,页面加载完毕后计算和重设两边的高度为最大的高度,当页面resize的时候再次处罚计算函数。

     

     

    $(document).ready(function () {
        var highestCol = Math.max($('#leftColumn').height(),$('#rightColumn').height());
        $('.elements').height(highestCol);      
    });
  2. 也比较简单的方法: table布局 。 因为这样就不需要js代码来控制(布局的事情还需要js来参与的话,有木有太业余的感觉?),而且不需要以下第三种方法的添加额外div。我这次使用的方法也是这一种的。

     

     

    .parent_div{display: table-cell;}
    .child_div{display:table-cell;height:100%;}
  3. 实用float来进行相关hack。 参考: http://matthewjamestaylor.com/blog/equal-height-columns-3-column.htm. 基本原理就是使用div 作为父类来对分栏的内容带来影响。 这种方法在两列、三列时使用还是比较方便的,但是如果随着列数增多,额外需要添加的div太多了,“好大一棵树的感觉”。以下代码是使用这种方法构造的三列布局(例子也来自 MATTHEW JAMES TAYLOR 的文章 Equal Height Columns with Cross-Browser CSS):
    如果使用默认的流式布局,代码如下:

     

    <div id="container1">
        <div id="col1">Column 1</div>
        <div id="col2">Column 2</div>
        <div id="col3">Column 3</div>
    </div>
    #container1 {
        float:left;
        width:100%;
    }
    #col1 {
        float:left;
        width:30%;
        background:red;
    }
    #col2 {
        float:left;
        width:40%;
        background:yellow;
    }
    #col3 {
        float:left;
        width:30%;
        background:green;
    }

    将会呈现如下效果:
    1equal-height-columns-container-div
    如果想要实现脱离子元素左右排列,则需要子元素使用float来脱离流式布局。如果再使父元素也浮动起来,则子元素的高度会把父元素的高度撑起来(要不然因为子元素脱离了文档流,去了另一个世界,父元素里东西都不存在了,父元素的高度就为0 了 。但是如果父子同时脱离了标准文档流,虽然都到了另一个世界,但dom结构在那里呢,还是父子关系,父亲下面又有儿子了,有内容了当然就有高度了,而且高度还是儿子的高度呢)。
    html: 

    <div id="container3">
        <div id="container2">
            <div id="container1">
                <div id="col1">Column 1</div>
                <div id="col2">Column 2</div>
                <div id="col3">Column 3</div>
            </div>
        </div>
    </div>

    css:
     

    #container3 {
        float:left;
        width:100%;
        background:green;
    }
    #container2 {
        float:left;
        width:100%;
        background:yellow;
    }
    #container1 {
        float:left;
        width:100%;
        background:red;
    }
    #col1 {
        float:left;
        width:30%;
    }
    #col2 {
        float:left;
        width:40%;
    }
    #col3 {
        float:left;
        width:30%;
    }

    这时显示结果如下:
    2equal-height-columns-3-containers
    现在高度已经正常了,下面只需要我们借助外层了父亲来下换脸,更改背景属性就行了:
    3equal-height-columns-container-positions
    将三列元素重新添加到页面上:
    4equal-height-columns-content-position
    contain1添加overflow兼容:
    5equal-height-columns-complete
    同时我们再给最外层的父亲(不做移位操作的dom,width为100%)加上overflow=hidden,从而让多出的内容不要展示出来
    css如下:

    #container3 {
        float:left;
        width:100%;
        background:green;
        overflow:hidden;
        position:relative;
    }
    #container2 {
        float:left;
        width:100%;
        background:yellow;
        position:relative;
        right:30%;
    }
    #container1 {
        float:left;
        width:100%;
        background:red;
        position:relative;
        right:40%;
    }
    #col1 {
        float:left;
        width:30%;
        position:relative;
        left:70%;
    }
    #col2 {
        float:left;
        width:40%;
        position:relative;
        left:70%;
    }
    #col3 {
        float:left;
        width:30%;
        position:relative;
        left:70%;
    }

    如果还需要在元素上加点内边距,也是可以的。依照以下计算方法:(每个元素加上2% 的边距):
    6equal-height-columns-3-column-offsets
    这种方法主要是为了兼容ie的,因为ie的双边距问题,如果我们的box是200像素,padding为20像素, 正常情况下这个元素宽度应该是240像素,但是IE下就是200像素。IE就是不认为padding是box的一部分。

本文即将结束时发现已有老外在几年前写的一篇文章,大意相同,而且分析的更有深度。 有空我会把这篇文章翻译出来,以释相见恨晚之情:(原文地址: https://css-tricks.com/fluid-width-equal-height-columns/