通过version方法来区分出IPv4和IPv6
>>> import IPy
>>> IPy.IP(‘10.0.0.0/8’).version()
4
>>> IPy.IP(‘::1’).version()
6
通过指定的网段输出该网段的IP个数和所有的IP地址清单

如下:

$ more ip.py
#!/usr/bin/env python
import IPy

ip = IPy.IP(‘192.168.0.0/16’)
print ip.len()
for x in ip:
print x
反向解析名称、IP类型、IP转换等

>>> ip = IP(‘192.168.1.20’)
>>> ip.reverseNames() #反向解析地址格式
[‘20.1.168.192.in-addr.arpa.’] >>> ip.iptype() #私网类型
‘PRIVATE’
>>> IP(‘8.8.8.8’).iptype() #公网类型
‘PUBLIC’
>>> IP(‘8.8.8.8’).int() #转换为整型格式
134744072
>>> IP(‘8.8.8.8’).strHex() #转换为十六进制格式
‘0x8080808’
>>> IP(‘8.8.8.8’).strBin() #转换成二进制格式
‘00001000000010000000100000001000’
>>> print IP(‘0x8080808’) #十六进制转换为IP格式
8.8.8.8
>>> print IP(134744072) #整型格式转换为IP格式
8.8.8.8
IP方法也支持网络地址的转换,例如根据IP和掩码产生网段格式

>>> print (IP(‘192.168.1.0’).make_net(‘255.255.255.0’))
192.168.1.0/24
>>> print (IP(‘192.168.1.0/255.255.255.0’,make_net=True))
192.168.1.0/24
>>> print (IP(‘192.168.1.0-192.168.1.255’,make_net=True))
192.168.1.0/24
通过strNormal方法指定不同wantprefixlen参数值以定制不同输出类型的网段,输出类型为字符串

>>> IP(‘192.168.1.0/24’).strNormal(0) #无返回
‘192.168.1.0’
>>> IP(‘192.168.1.0/24’).strNormal(1) #prefix格式
‘192.168.1.0/24’
>>> IP(‘192.168.1.0/24’).strNormal(2) #decimalnetmask格式
‘192.168.1.0/255.255.255.0’
>>> IP(‘192.168.1.0/24’).strNormal(3) #lastIP格式
‘192.168.1.0-192.168.1.255’
多网络计算方法详解
比较两个网段是否存在包含、重叠等关系,比如同网络但不同prefixlen会认为是不相等的网段,如10.0.0.0/16不等于10.0.0.0/24,另外即使具有相同的prefixlen但处于不同的网络地址,同样也视为不相等,如10.0.0.0/16不等于192.0.0.0/16。IPy支持类似于数值型数据的比较,以帮助IP对象进行比较。

比较IP大小

>>> IP(‘10.0.0.0/24’) < IP(‘12.0.0.0/24’)
True
判断IP地址和网段是否包含于另一个网段中

>>> ‘192.168.1.100’ in IP(‘192.168.1.0/24’)
True
>>> IP(‘192.168.1.0/24’) in IP(‘192.168.0.0/16’)
True
判断两个网段是否存在重叠(overlaps方法)

>>> IP(‘192.168.0.0/23’).overlaps(‘192.168.1.0/24’)
1
>>> IP(‘192.168.1.0/24’).overlaps(‘192.168.2.0/24’)
0

一般情况下我们在HTML中使用POST提交数据的时候,一般POST表单代码如下:

<form method="post"action=# >
         <input type="text" name="txt1" value="txt1"></br>
         <input type="text" name="txt2" value="txt2"></br>
         <input type="submit" value="Submit"">
</form>

可以看到POST请求如下:

POST /test.php HTTP/1.1
Host: 172.16.100.168
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://172.16.100.168/test.php
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 19

txt1=txt1&txt2=txt2

其中Content-Type为application/x-www-form-urlencoded。这意味着消息内容会经过URL编码。
获取到POST内容的lua代码如下:

ngx.req.read_body()
for k,v in pairs(ngx.req.get_post_args()) do
    ngx.say(k..":"..v)
end

默认情况下不会读取POST的内容,需要ngx.req.read_body()来开启。也可以在nginx配置中直接使用lua_need_request_body开启。
另外如果提交的数据Content-length大于client_body_buffer_size的设置,那么req.get_post_args()会获取不到数据。

最早的HTTP POST是不支持文件上传的,后来Content-Type的类型扩充了multipart/form-data用以支持向服务器发送二进制数据。
其实form表单在你不写enctype属性时,也默认为其添加了enctype属性值,默认值是enctype=”application/x- www-form-urlencoded”.
我们修改表单的内容如下:

<form method="post"action=# enctype="multipart/form-data">
         <input type="text" name="txt1" value="txt1"></br>
         <input type="text" name="txt2" value="txt2"></br>
         <input type="submit" value="Submit"">
</form>
<?php
echo $_POST['txt1'];
echo $_POST['txt2']
?>

POST请求数据包如下:

POST /test.php HTTP/1.1
Host: 172.16.100.168
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://172.16.100.168/test.php
Connection: close
Content-Type: multipart/form-data; boundary=---------------------------285751406325668
Content-Length: 246

-----------------------------285751406325668
Content-Disposition: form-data; name="txt1"

txt1
-----------------------------285751406325668
Content-Disposition: form-data; name="txt2"

txt2
-----------------------------285751406325668--

可以看到Content-Type变为multipart/form-data; 里面的内容是不经过URL编码的。
读取文件内容的代码如下:
ngx.req.read_body()
ngx.say(ngx.req.get_body_data())
然后返回结果如图:

123

ngx.req.get_body_data()
存在两种情况是会将body内容写入到文件中导致获取不到
1)body体大于设置的client_body_buffer_size(在32位系统中默认为8K,在64位系统中默认为16K)
2)client_body_in_file_only打开
例如上传一个800k的图片,打印的内容就是nil。
然后我们修改lua代码如下:

ngx.req.read_body()
if ngx.req.get_body_data() ~= nil then
    ngx.say(ngx.req.get_body_data())
else
    ngx.say(ngx.req.get_body_file())
end

然后上传800K的图片,返回结果如图:
123

返回了临时文件的图片路径。
然后我们再修改一下lua代码,读取临时文件的内容

ngx.req.read_body()
if ngx.req.get_body_data() ~= nil then
    ngx.say(ngx.req.get_body_data())
else
    RulePath = ngx.req.get_body_file()
    ngx.say(RulePath)
    file = io.open(RulePath,"r")
    if file==nil then
        return
    end
    file:seek("set")--设置从文件头开始读取
    --ngx.say(file:read("*a"))--从当前位置读取整个文件
    ngx.say(file:read(1000))--从当前位置读取1000个字节
    file:close()
end

这样就可以读取到了POST的内容。

1)
LuaJIT即采用C语言写的Lua的解释器的代码。

wget http://luajit.org/download/LuaJIT-2.0.3.tar.gz
tar xf LuaJIT-2.0.3.tar.gz
cd LuaJIT-2.0.3
make && make install
ln -sv /usr/local/lib/libluajit-5.1.so.2.0.3 /lib64/libluajit-5.1.so.2

下载ngx_devel_kit并解压
2)

wget https://github.com/simpl/ngx_devel_kit/archive/v0.2.19.tar.gz
tar zxvf v0.2.19.tar.gz

下载ngx_lua并解压
3)

wget https://github.com/chaoslawful/lua-nginx-module/archive/v0.9.6.tar.gz
tar zxvf v0.9.6.tar.gz

4)
重新编译安装nginx

./configure  --with-pcre --add-module=/opt/lua-nginx-module-0.9.6 --add-module=/opt/ngx_devel_kit-0.2.19 
make && make install

原来用python多行匹配的时候都是用[\s\S] 今天发现使用re.S即可匹配多行
1)如果你要多行匹配,那么需要加上re.S和re.M标志. 加上re.S后, .将会匹配换行符,默认.不会匹配换行符. 代码如下:
str = "a23b\na34b"
re.findall(r"a(\d+)b.+a(\d+)b", str)
#输出[] #因为不能处理str中间有\n换行的情况
re.findall(r"a(\d+)b.+a(\d+)b", str, re.S)
#s输出[(’23’, ’34’)] 2)加上re.M后,^$标志将会匹配每一行,默认^和$只会匹配第一行. 代码如下:
str = "a23b\na34b"
re.findall(r"^a(\d+)b", str)
#输出[’23’] re.findall(r"^a(\d+)b", str, re.M)
#输出[’23’, ’34’]

logstash中自定义正则就是使用了这种方式
将%{SYNTAX:SEMANTIC} 写为(?<SEMANTIC>regexp)
这种情况我们可以使用(?P<name>…)这个正则表达式来提取. 举例,如果我们有一行webserver的access日志:'192.168.0.1 25/Oct/2012:14:46:34 "GET /api HTTP/1.1" 200 44 "http://abc.com/search" "Mozilla/5.0"',我们想提取这行日志里面所有的内容,可以写多个(?P<name>expr)来提取,其中name可以更改为你为该位置字符串命名的变量,expr改成提取位置的正则即可. 代码如下:

import re
line ='192.168.0.1 25/Oct/2012:14:46:34 "GET /api HTTP/1.1" 200 44 "http://abc.com/search" "Mozilla/5.0"'
reg = re.compile('^(?P[^ ]*) (?P[^ ]*) "(?P[^"]*)" (?P[^ ]*) (?P[^ ]*) "(?P[^"]*)" "(?P[^"]*)"')
regMatch = reg.match(line)
linebits = regMatch.groupdict()
print linebits
for k, v in linebits.items() :
print k+": "+v

返回结果为:
E:\Python27\python.exe E:/Pycharm/node.py
{'status': '200', 'referrer': 'http://abc.com/search', 'request': 'GET /api HTTP/1.1', 'user_agent': 'Mozilla/5.0', 'date': '25/Oct/2012:14:46:34', 'size': '44', 'remote_ip': '192.168.0.1'}
status: 200
referrer: http://abc.com/search
request: GET /api HTTP/1.1
user_agent: Mozilla/5.0
date: 25/Oct/2012:14:46:34
size: 44
remote_ip: 192.168.0.1

Process finished with exit code 0

# -*- coding: utf8 -*-
from time import strftime, localtime
from datetime import timedelta, date
import time
import json
import datetime
import sqlite3
import os
import nmap
import sys
reload(sys)
sys.setdefaultencoding( "utf-8" )
def nmapscan(ip):
    nm = nmap.PortScanner()
    nm.scan(hosts=ip,ports='80,3306,9200')
    print nm.scaninfo()
    print nm.command_line() 
    for host in nm.all_hosts():
        for proto in nm[host].all_protocols():
            lport = nm[host][proto].keys()
            lport.sort()
            count_port = len(lport)
            i = 0
            while i < count_port:
                in_port = lport[i]
                if nm[host][proto][in_port]['state'] == 'open':
                    print host + ":" + str(in_port) + " => " + nm[host][proto][in_port]['name']
                i+=1
if __name__ == '__main__':
    start = time.time()
    nmapscan('10.59.0.116')
    end = time.time()
    print "程序执行时间:" + str(int(end - start)) + "s"

执行结果为:
[root@server120 tmp]# python thread.py
{‘tcp’: {‘services’: ‘80,3306,9200’, ‘method’: ‘syn’}}
nmap -oX – -p 80,3306,9200 -sV 10.59.0.116
10.59.0.116:80 => http
10.59.0.116:9200 => wap-wsp
程序执行时间:90s

默认的执行参数如下:
nmap -oX – -p 80,3306,9200 -sV 10.59.0.116
使用-sV会尝试探测端口的服务类型/具体版本等信息,速度慢一些,可以尝试修改nmap参数
nm.scan(hosts=ip,arguments=’-sS -p 80,3306,9200′)
执行结果:
[root@server120 tmp]# python thread.py
{‘tcp’: {‘services’: ‘80,3306,9200’, ‘method’: ‘syn’}}
nmap -oX – -sS -p 80,3306,9200 10.59.0.116
10.59.0.116:80 => http
10.59.0.116:9200 => wap-wsp
程序执行时间:5s
可以看出执行时间缩短了很多

# -*- coding: utf8 -*-
import socket
import sys
import threading
import time
import Queue
TIMEOUT = 2
reload(sys)
sys.setdefaultencoding( "utf-8" )
def scan(ip, port, timeout=TIMEOUT):
    try:
        print "Scan " + ip + "  " + str(port)
        cs = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        cs.settimeout(float(timeout))
        address = (str(ip), int(port))
        status = cs.connect_ex((address))
        if status == 0:
            print "%s ==> %d" % (ip,port)
    except Exception, e:
        print "error:%s" % e
    finally:
        cs.close()
class Scan(threading.Thread):
    def __init__(self, queue):
        threading.Thread.__init__(self)
        self.queue = queue
    def run(self):
        while True:
            try:
                if queue.empty(): break
                queue_task = self.queue.get()
                ip = queue_task.split(':')[0]
                port = int(queue_task.split(':')[1])
                scan(ip,port)
            except:
                break
def get_ip_list(ip):
    ip_list = []
    iptonum = lambda x:sum([256**j*int(i) for j,i in enumerate(x.split('.')[::-1])])
    numtoip = lambda x: '.'.join([str(x/(256**i)%256) for i in range(3,-1,-1)])
    if '-' in ip:
        ip_range = ip.split('-')
        ip_start = long(iptonum(ip_range[0]))
        ip_end = long(iptonum(ip_range[1]))
        ip_count = ip_end - ip_start
        if ip_count >= 0 and ip_count <= 65536:
            for ip_num in range(ip_start,ip_end+1):
                ip_list.append(numtoip(ip_num))
        else:
            print 'ERROR'
    else:
        ip_split = ip.split('.')
        net = len(ip_split)
        if net == 2:
            for b in range(1, 255):
                for c in range(1, 255):
                    ip = "%s.%s.%d.%d" % (ip_split[0], ip_split[1], b, c)
                    ip_list.append(ip)
        elif net == 3:
            for c in range(1, 255):
                ip = "%s.%s.%s.%d" % (ip_split[0], ip_split[1], ip_split[2], c)
                ip_list.append(ip)
        elif net == 4:
            ip_list.append(ip)
        else:
            print "ERROR"
    return ip_list
if __name__ == '__main__':
    queue = Queue.Queue()
    port = ['80','9200','443','3306']
    ip = '192.168.190.1-192.168.190.50'
    for ipaddress in get_ip_list(ip):
        for p in port:
            queue.put(ipaddress+":"+p)
    threads = []
    num = 10 #设置线程数
    for x in xrange(0, num):
        t_scan = Scan(queue)
        threads.append(t_scan)
    for t in threads:
        t.start()
    for t in threads:
        t.join()

先看一段程序:


import threading,time
from time import sleep, ctime
def now() :
return str( time.strftime( '%Y-%m-%d %H:%M:%S' , time.localtime() ) )
def test(nloop, nsec):
print 'start loop', nloop, 'at:', now()
sleep(nsec)
print 'loop', nloop, 'done at:', now()
def main():
print 'starting at:',now()
threadpool=[] for i in xrange(3):
th = threading.Thread(target= test,args= (i,2))
threadpool.append(th)
#th.setDaemon(True)
for th in threadpool:
th.start()
print 'all Done at:', now()
if __name__ == '__main__':
main()

如果不加join和setDaemon的话,输出如下:

123

如果添加join(),输出如下:
for th in threadpool :
threading.Thread.join( th )

123

可以看到主线程是最后才结束的,join() 的作用是,在子线程完成运行之前,这个子线程的父线程将一直被阻塞。
然后我们添加一下setDeamon
for i in xrange(3):
th = threading.Thread(target= test,args= (i,2))
threadpool.append(th)
th.setDaemon(True)

123

可以看到主线程结束之后,子线程也会结束。
我们可以添加锁试验一下:

import threading,time
from time import sleep, ctime
def now() :
return str( time.strftime( '%Y-%m-%d %H:%M:%S' , time.localtime() ) )
def test(nloop, nsec):
mutex.acquire()
print 'start loop', nloop, 'at:', now()
sleep(nsec)
print 'loop', nloop, 'done at:', now()
mutex.release()
def main():
print 'starting at:',now()
threadpool=[] for i in xrange(3):
th = threading.Thread(target= test,args= (i,2))
threadpool.append(th)
#th.setDaemon(True)
for th in threadpool:
th.start()
for th in threadpool :
threading.Thread.join( th )
print 'all Done at:', now()
if __name__ == '__main__':
mutex = threading.Lock()
main()


输出如下:

123

Python的多线程是鸡肋,只能在单核上跑,在任意时间只有一个Python解释器在解释Python bytecode。但是Python的多线程也并非一无是处。
如果你的代码是CPU密集型,多个线程的代码很有可能是线性执行的。所以这种情况下多线程是鸡肋,效率可能还不如单线程因为有context switch。
如果你的代码是IO密集型,多线程可以明显提高效率。例如爬虫,因为绝大多数时间爬虫是在等待socket返回数据。
CPU密集型的代码可以选择使用multiprocessing库。

threading模块里面主要是对一些线程的操作对象化,创建Thread的class。一般来说,使用线程有两种模式:
A 创建线程要执行的函数,把这个函数传递进Thread对象里,让它来执行。
B 继承Thread类,创建一个新的class,将要执行的代码 写到run函数里面。

第一种 创建线程要执行的函数,把这个函数传递进Thread对象里,让它来执行。

import threading,time
from time import sleep, ctime
def now() :
    return str( time.strftime( '%Y-%m-%d %H:%M:%S' , time.localtime() ) )

def test(nloop, nsec):
    print 'start loop', nloop, 'at:', now()
    sleep(nsec)
    print 'loop', nloop, 'done at:', now()

def main():
    print 'starting at:',now()
    threadpool=[]

    for i in xrange(3):
        th = threading.Thread(target= test,args= (i,2))
        threadpool.append(th)

    for th in threadpool:
        th.start()

    for th in threadpool :
        threading.Thread.join( th )

    print 'all Done at:', now()

if __name__ == '__main__':
        main()

第二种:继承Thread类,创建一个新的class,将要执行的代码 写到run函数里面。

import threading ,time
from time import sleep, ctime
def now() :
    return str( time.strftime( '%Y-%m-%d %H:%M:%S' , time.localtime() ) )

class myThread (threading.Thread) :
      """docstring for myThread"""
      def __init__(self, nloop, nsec) :
          super(myThread, self).__init__()
          self.nloop = nloop
          self.nsec = nsec

      def run(self):
          print 'start loop', self.nloop, 'at:', ctime()
          sleep(self.nsec)
          print 'loop', self.nloop, 'done at:', ctime()
def main():
     thpool=[]
     print 'starting at:',now()
    
     for i in xrange(10):
         thpool.append(myThread(i,2))
       
     for th in thpool:
         th.start()
   
     for th in thpool:
         th.join()
    
     print 'all Done at:', now()

if __name__ == '__main__':
        main()

virtualenv就是用来为一个应用创建一套“隔离”的Python运行环境。
[root@server120 ~]# pip install virtualenv
[root@server120 tmp]# mkdir vinc
[root@server120 tmp]# cd vinc/
创建一个独立的Python运行环境,命名为venv:
[root@server120 vinc]# virtualenv –no-site-packages venv
New python executable in /tmp/vinc/venv/bin/python
Installing setuptools, pip, wheel…done.
命令virtualenv就可以创建一个独立的Python运行环境,我们还加上了参数–no-site-packages,这样,已经安装到系统Python环境中的所有第三方包都不会复制过来,这样,我们就得到了一个不带任何第三方包的“干净”的Python运行环境。

[root@server120 vinc]# . venv/bin/activate
(venv) [root@server120 vinc]#
注意到命令提示符变了,有个(venv)前缀,表示当前环境是一个名为venv的Python环境。
在venv环境下,用pip安装的包都被安装到venv这个环境下,系统Python环境不受任何影响。也就是说,venv环境是专门针对vinc这个应用创建的。
退出当前的venv环境,使用deactivate命令:
(venv) [root@server120 vinc]# deactivate
[root@server120 vinc]#