[实践OK]相当有用之频率测试 curl 时间 CURL一行时间参数/curl获取网络时间访问多次测试网页响应时间的shell脚本,需要Curl支持,Curl测试访问时间,DNS解析时间。
Php/Js/Shell/Go jackxiang 2013-6-6 12:02
背景:一天突然发现访问网站特别的慢,怎么办?原因是啥,不知道,此时,祭出CURL,加上相关的数据输出,特别是对于DNS慢这种问题最难查,居然被我碰到了,time_namelookup 这个参数很重要,DNS解析时间,从请求开始到DNS解析完毕所用时间(记得关掉 Linux 的 nscd 的服务测试),当然,查dns更为直观的是用curl的-H参数(http://jackxiang.com/post/4423/),不用dns解析时的一个指标,再就是用dns解析的一个指标,一对比就出来了,该命令在windows下使用也没问题。
DNS解析时的时间:
5.011:5.011:5.020:5.020:
不用DNS相当于写死Host解析时的办法:
0.003:0.003:0.026:0.026
time_namelookup时间5.011太长了,说明DNS有问题,一查果然有问题,由于此内网DNS解析了单位办工机器,还解析线上服务器内部域名,压力太大导致,为此,新加了一台dns服务器,减轻压力,解析的速度上去了,也就好了。
相关参数解释:
time_connect 建立到服务器的 TCP 连接所用的时间
time_starttransfer 在发出请求之后,Web 服务器返回数据的第一个字节所用的时间
time_total 完成请求所用的时间
time_namelookup DNS解析时间,从请求开始到DNS解析完毕所用时间(记得关掉 Linux 的 nscd 的服务测试)
speed_download 下载速度,单位-字节每秒。(注意它是字节)
[/codes]
来个实例:
加上字节:
time函数实现时间:
加上Shell的for循环,一般主要是打印时间:
粘贴好像会报错,直接给个DownLoad:
sh curlExecuteTime.sh -n 12 "http://localhost"
**春(**春) 11:11:56
time_connect: 0.001
time_namelookup: 0
time_total: 0.01419
**春(**春) 11:12:18
这个结果按说是没问题的吧
向东(向东) 11:12:34
没问题,你要想获取接口返回修改下这儿:curl -o /dev/null -s -w \
向东(向东) 11:12:42
它定向到null了。
向东(向东) 11:21:16
c=`curl -o /tmp/$i.txt -s -w \
这样就可以在tmp下生成1.txt 2.txt了,呵呵。
DownLoad:
零:可以直接用shell实现,用vim列模式/行模式进行批量输入,当然也可以用shell的for循环,如出现301错误需要输出头-i,如下:
一:PHP下的Curl获取时间 :
二:Shell下的curl原理:
curl -o /dev/null -s -w '连接时间:%{time_connect},传输时间:%{time_starttransfer}:%{time_total}' "http://jackxiang.com"
POST示例(不用-o写入文件,直接看):
用法及返回结果如下:
lvyaozu@lvyaozu-desktop:~/shell$ ./requesturl.sh -n20 http://www.baidu.com
Request url: http://www.baidu.com
Request number: 20
Request Failed: 0
——Average Value——
time_connect: 0.1614
time_total: 0.1693
time_namelookup: 0.0088
————————-
请求参数:
-n 指定发送多少次请求,默认为10
返回结果为 curl -w 选项返回值,以下摘自curl官方文档:
http://curl.haxx.se/docs/manpage.html
time_connect The time, in seconds, it took from the start until the TCP connect to the remote host (or proxy) was completed.
time_total The total time, in seconds, that the full operation lasted. The time will be displayed with millisecond resolution.
time_namelookup The time, in seconds, it took from the start until the name resolving was completed.
代码如下:
我的实践如下:
sh curlExecuteTime.sh -n 12 "http://jackxiang.com/getAlbumsByUId?appkey=100&userid=21240168&sortby=hot"
Request url: hhttp://jackxiang.com/getAlbumsByUId?appkey=100&userid=21240168&sortby=hot
Request number: 12
Request Failed: 0
------Average Value------
time_connect: 0.001
time_namelookup: 0.001
time_total: 0.0760833
-------------------------
来自:http://renxiangzyq.iteye.com/blog/782773
1、开启gzip请求
curl -I http://www.sina.com.cn/ -H Accept-Encoding:gzip,defalte
2、监控网页的响应时间
curl -o /dev/null -s -w "time_connect: %{time_connect}\ntime_starttransfer: %{time_starttransfer}\ntime_total: %{time_total}\n" "http://www.kklinux.com"
3. 监控站点可用性
curl -o /dev/null -s -w %{http_code} "http://www.kklinux.com"
4、以http1.0协议请求(默认为http1.1)
curl -0 ..............
监控站点首页下载时间:
curl -o /dev/null -s -w ‘%{time_total}’ http://www.miotour.com
curl -o /dev/null -s -w ‘%{http_code}’ http://www.miotour.com
curl -o /dev/null -s -w %{http_code}:%{time_connect}:%{time_starttransfer}:%{time_total} http://www.miotour.com
结果:2.547
-s 静默输出;没有-s的话就是下面的情况,这是在脚本等情况下不需要的信息。
[ec2-user@ip-10-122-250-19 ~]$ curl -o /dev/null -w ‘%{time_total}’ http://www.miotour.com
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 67770 0 67770 0 0 19228 0 –:–:– 0:00:03 –:–:– 20705
结果:3.524
监控首页各项时间指标:
curl -o /dev/null -s -w ‘%{time_connect}:%{time_starttransfer}:%{time_total}’ http://www.miotour.com
结果: 0.244: 1.044: 2.672
时间指标解释 :
time_connect 建立到服务器的 TCP 连接所用的时间
time_starttransfer 在发出请求之后,Web 服务器返回数据的第一个字节所用的时间
time_total 完成请求所用的时间
在 发出请求之后,Web 服务器处理请求并开始发回数据所用的时间是
(time_starttransfer)1.044 - (time_connect)0.244 = 0.8 秒
客户机从服务器下载数据所用的时间是
(time_total)2.672 - (time_starttransfer)1.044 = 1.682 秒
指定特定主机IP地址访问网站
curl -x 61.135.169.105:80 http://www.baidu.com
curl -x 61.135.169.125:80 http://www.baidu.com
摘录来自:http://blog.163.com/dingding_jacky/blog/static/166912787201242440274/
DNS解析时的时间:
5.011:5.011:5.020:5.020:
不用DNS相当于写死Host解析时的办法:
0.003:0.003:0.026:0.026
time_namelookup时间5.011太长了,说明DNS有问题,一查果然有问题,由于此内网DNS解析了单位办工机器,还解析线上服务器内部域名,压力太大导致,为此,新加了一台dns服务器,减轻压力,解析的速度上去了,也就好了。
相关参数解释:
time_connect 建立到服务器的 TCP 连接所用的时间
time_starttransfer 在发出请求之后,Web 服务器返回数据的第一个字节所用的时间
time_total 完成请求所用的时间
time_namelookup DNS解析时间,从请求开始到DNS解析完毕所用时间(记得关掉 Linux 的 nscd 的服务测试)
speed_download 下载速度,单位-字节每秒。(注意它是字节)
[/codes]
来个实例:
加上字节:
time函数实现时间:
加上Shell的for循环,一般主要是打印时间:
粘贴好像会报错,直接给个DownLoad:
下载文件
sh curlExecuteTime.sh -n 12 "http://localhost"
**春(**春) 11:11:56
time_connect: 0.001
time_namelookup: 0
time_total: 0.01419
**春(**春) 11:12:18
这个结果按说是没问题的吧
向东(向东) 11:12:34
没问题,你要想获取接口返回修改下这儿:curl -o /dev/null -s -w \
向东(向东) 11:12:42
它定向到null了。
向东(向东) 11:21:16
c=`curl -o /tmp/$i.txt -s -w \
这样就可以在tmp下生成1.txt 2.txt了,呵呵。
DownLoad:
下载文件
零:可以直接用shell实现,用vim列模式/行模式进行批量输入,当然也可以用shell的for循环,如出现301错误需要输出头-i,如下:
一:PHP下的Curl获取时间 :
二:Shell下的curl原理:
curl -o /dev/null -s -w '连接时间:%{time_connect},传输时间:%{time_starttransfer}:%{time_total}' "http://jackxiang.com"
POST示例(不用-o写入文件,直接看):
用法及返回结果如下:
lvyaozu@lvyaozu-desktop:~/shell$ ./requesturl.sh -n20 http://www.baidu.com
Request url: http://www.baidu.com
Request number: 20
Request Failed: 0
——Average Value——
time_connect: 0.1614
time_total: 0.1693
time_namelookup: 0.0088
————————-
请求参数:
-n 指定发送多少次请求,默认为10
返回结果为 curl -w 选项返回值,以下摘自curl官方文档:
http://curl.haxx.se/docs/manpage.html
time_connect The time, in seconds, it took from the start until the TCP connect to the remote host (or proxy) was completed.
time_total The total time, in seconds, that the full operation lasted. The time will be displayed with millisecond resolution.
time_namelookup The time, in seconds, it took from the start until the name resolving was completed.
代码如下:
我的实践如下:
sh curlExecuteTime.sh -n 12 "http://jackxiang.com/getAlbumsByUId?appkey=100&userid=21240168&sortby=hot"
Request url: hhttp://jackxiang.com/getAlbumsByUId?appkey=100&userid=21240168&sortby=hot
Request number: 12
Request Failed: 0
------Average Value------
time_connect: 0.001
time_namelookup: 0.001
time_total: 0.0760833
-------------------------
来自:http://renxiangzyq.iteye.com/blog/782773
1、开启gzip请求
curl -I http://www.sina.com.cn/ -H Accept-Encoding:gzip,defalte
2、监控网页的响应时间
curl -o /dev/null -s -w "time_connect: %{time_connect}\ntime_starttransfer: %{time_starttransfer}\ntime_total: %{time_total}\n" "http://www.kklinux.com"
3. 监控站点可用性
curl -o /dev/null -s -w %{http_code} "http://www.kklinux.com"
4、以http1.0协议请求(默认为http1.1)
curl -0 ..............
监控站点首页下载时间:
curl -o /dev/null -s -w ‘%{time_total}’ http://www.miotour.com
curl -o /dev/null -s -w ‘%{http_code}’ http://www.miotour.com
curl -o /dev/null -s -w %{http_code}:%{time_connect}:%{time_starttransfer}:%{time_total} http://www.miotour.com
结果:2.547
-s 静默输出;没有-s的话就是下面的情况,这是在脚本等情况下不需要的信息。
[ec2-user@ip-10-122-250-19 ~]$ curl -o /dev/null -w ‘%{time_total}’ http://www.miotour.com
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 67770 0 67770 0 0 19228 0 –:–:– 0:00:03 –:–:– 20705
结果:3.524
监控首页各项时间指标:
curl -o /dev/null -s -w ‘%{time_connect}:%{time_starttransfer}:%{time_total}’ http://www.miotour.com
结果: 0.244: 1.044: 2.672
时间指标解释 :
time_connect 建立到服务器的 TCP 连接所用的时间
time_starttransfer 在发出请求之后,Web 服务器返回数据的第一个字节所用的时间
time_total 完成请求所用的时间
在 发出请求之后,Web 服务器处理请求并开始发回数据所用的时间是
(time_starttransfer)1.044 - (time_connect)0.244 = 0.8 秒
客户机从服务器下载数据所用的时间是
(time_total)2.672 - (time_starttransfer)1.044 = 1.682 秒
指定特定主机IP地址访问网站
curl -x 61.135.169.105:80 http://www.baidu.com
curl -x 61.135.169.125:80 http://www.baidu.com
摘录来自:http://blog.163.com/dingding_jacky/blog/static/166912787201242440274/
[接口超时]在Nginx里的PHP输出接口进行strace时发现的超时问题备案,有可能是Mysql Server里域名解析导致。
Php/Js/Shell/Go jackxiang 2013-6-5 18:17
Nginx里有一个PHP的接口,发现是PHP的超时,于是经过strace时发现:
经过xdebug发现它是由于数据库访问这个函数超时引起的,有5秒到15秒之多,但是把这个SQL贴在终端里访问,发现它很快才几毫秒。
用下面的sleep代码也能形成TimeOut,如下:
我在想,是192.168.109.8访问192.168.109.7上中间有时会有波动造成的,还是因为PHP连接时超时呢?需要进一步了解啊。
有一个域名反解的配置把这个去掉:
skip-name-resolve
修改配置文件添加并需要重启:
修改my.cnf的配置文件添加并需要重启,试试:
[mysqld]
skip-name-resolve
感觉通过一个脚本访问好像好了,需要时间验证,脚本:
http://www.jackxiang.com/post/6421/
经过xdebug发现它是由于数据库访问这个函数超时引起的,有5秒到15秒之多,但是把这个SQL贴在终端里访问,发现它很快才几毫秒。
用下面的sleep代码也能形成TimeOut,如下:
我在想,是192.168.109.8访问192.168.109.7上中间有时会有波动造成的,还是因为PHP连接时超时呢?需要进一步了解啊。
有一个域名反解的配置把这个去掉:
skip-name-resolve
修改配置文件添加并需要重启:
修改my.cnf的配置文件添加并需要重启,试试:
[mysqld]
skip-name-resolve
感觉通过一个脚本访问好像好了,需要时间验证,脚本:
http://www.jackxiang.com/post/6421/
nginx里的keepalive-timeout选项
此选项说的是可使客户端到服务器端的连接持续有效,当出现对服务器的后继请求时,keepalive-timeout功能可避免建立或重新建立连接。
涉及的选项还有stub_status on,能看到waiting值也和keepalive-timeout设置有关
nginx不像apache,直接有指令keep-alive off/on;它使用的是keepalive_timeout [time],默认的时长为75,可以在http、server、location使用此指令。
在本机进行的模拟测试:
nginx.conf
keepalive_timeout 600;
curl -i Url //i 显示Http头
HTTP/1.1 200 OK
Server: nginx
Date: Wed, 05 Jun 2013 07:57:06 GMT
Content-Type: text/html;charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Accept-Encoding
Cache-Control: no-cache
Pragma: no-cache
nginx.conf指定的VHOST中添加了规则:
location /gtj/ {
alias C:/phpApp/gtj/;
keepalive_timeout 0;
expires 5m;
}
客户端请求后,可以用httpwatch抓取返回的头部信息:
Http头:
connection close
HTTP/1.1 200 OK
Server: nginx
Date: Wed, 05 Jun 2013 07:59:40 GMT
Content-Type: text/html;charset=utf-8
Transfer-Encoding: chunked
Connection: close
Vary: Accept-Encoding
Cache-Control: no-cache
Pragma: no-cache
阅读全文
此选项说的是可使客户端到服务器端的连接持续有效,当出现对服务器的后继请求时,keepalive-timeout功能可避免建立或重新建立连接。
涉及的选项还有stub_status on,能看到waiting值也和keepalive-timeout设置有关
nginx不像apache,直接有指令keep-alive off/on;它使用的是keepalive_timeout [time],默认的时长为75,可以在http、server、location使用此指令。
在本机进行的模拟测试:
nginx.conf
keepalive_timeout 600;
curl -i Url //i 显示Http头
HTTP/1.1 200 OK
Server: nginx
Date: Wed, 05 Jun 2013 07:57:06 GMT
Content-Type: text/html;charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Accept-Encoding
Cache-Control: no-cache
Pragma: no-cache
nginx.conf指定的VHOST中添加了规则:
location /gtj/ {
alias C:/phpApp/gtj/;
keepalive_timeout 0;
expires 5m;
}
客户端请求后,可以用httpwatch抓取返回的头部信息:
Http头:
connection close
HTTP/1.1 200 OK
Server: nginx
Date: Wed, 05 Jun 2013 07:59:40 GMT
Content-Type: text/html;charset=utf-8
Transfer-Encoding: chunked
Connection: close
Vary: Accept-Encoding
Cache-Control: no-cache
Pragma: no-cache
阅读全文
Linux系统密码忘记后的五种恢复方法
Unix/LinuxC技术 jackxiang 2013-6-4 09:48
vim对齐插件——Align
Unix/LinuxC技术 jackxiang 2013-6-1 23:26
https://github.com/tsaleh/vim-align
能满足各种方式的对齐。真心不错呢
能满足各种方式的对齐。真心不错呢
背景:
外包把代码放到我们的测试机上,有可能出现这样那样的调用问题,尽管前面说过要注意host配置的问题并记录,但是往往出现在上到测试机时,忘记了,于是用下tcpdump来抓包,可以实现有效的对其跨系统的接口进行跟踪,并找到问题之所在。
零:使用,方法一:
vi /root/.bashrc
生效:
source /root/.bashrc
方法二(优点这个导出只是传的参数以&符号分割,而返回则全是body里的内容,相当的适合用作接口调试参数,用curl来进行组装访问。):
参考其优点细说在:http://jackxiang.com/post/7344/
特别说明:
tcpdump命令默认捕获包总长度是96字节,如图所示,我们只要在抓包命令里加一个参数 -s 0 即可捕获完整数据的数据包。
/usr/local/sbin/tcpdump -i any -p -s 0 -w /tmp/capture.pcap
一:安装
官网:http://www.tcpdump.org
下载两个包,注意配套,我的是:
http://www.tcpdump.org/release/libpcap-1.4.0.tar.gz
http://www.tcpdump.org/release/tcpdump-4.3.0.tar.gz
Add Time:2014-01-27,上面旧版本没问题,新的有问题:
wget http://www.tcpdump.org/release/tcpdump-4.5.1.tar.gz
wget http://www.tcpdump.org/release/libpcap-1.5.3.tar.gz
1 下载了libpcap-1.5.2.tar.gz。
2 tar -vxf libpcap-1.5.2.tar.gz
3 ./configure
4 make 发生错误。
1)安装:libpcap
cd /data/codesdev/libpcap/libpcap-1.6.1
./configure&&make && make install
理论上一次能过,但是往往会出现新的问题,如下:
[root@master libpcap-1.5.2]# make
gcc -fpic -I. -I/usr/include/dbus-1.0 -I/usr/lib64/dbus-1.0/include -DHAVE_CONFIG_H -D_U_="__attribute__((unused))" -g -O2 -c ./pcap-dbus.c
./pcap-dbus.c: In function ‘dbus_write’:
./pcap-dbus.c:111: 错误:‘DBUS_ERROR_INIT’ 未声明 (在此函数内第一次使用)
./pcap-dbus.c:111: 错误:(即使在一个函数内多次出现,每个未声明的标识符在其
./pcap-dbus.c:111: 错误:所在的函数内只报告一次。)
./pcap-dbus.c: In function ‘dbus_activate’:
./pcap-dbus.c:165: 错误:‘DBUS_ERROR_INIT’ 未声明 (在此函数内第一次使用)
make: *** [pcap-dbus.o] 错误 1
按装dbus:
http://www.freedesktop.org/wiki/Software/dbus/
问题答案未实践来自:http://bbs.csdn.net/topics/390693013
######################我的情况如下######################
cc -fpic -I. -I/usr/include/dbus-1.0 -I/usr/lib64/dbus-1.0/include -DHAVE_CONFIG_H -D_U_="__attribute__((unused))" -g -O2 -c ./pcap-linux.c
gcc -fpic -I. -I/usr/include/dbus-1.0 -I/usr/lib64/dbus-1.0/include -DHAVE_CONFIG_H -D_U_="__attribute__((unused))" -g -O2 -c ./pcap-usb-linux.c
gcc -fpic -I. -I/usr/include/dbus-1.0 -I/usr/lib64/dbus-1.0/include -DHAVE_CONFIG_H -D_U_="__attribute__((unused))" -g -O2 -c ./pcap-dbus.c
./pcap-dbus.c: In function ‘dbus_write’:
./pcap-dbus.c:111: error: ‘DBUS_ERROR_INIT’ undeclared (first use in this function)
./pcap-dbus.c:111: error: (Each undeclared identifier is reported only once
./pcap-dbus.c:111: error: for each function it appears in.)
./pcap-dbus.c: In function ‘dbus_activate’:
./pcap-dbus.c:165: error: ‘DBUS_ERROR_INIT’ undeclared (first use in this function)
make: *** [pcap-dbus.o] Error 1
#########################################################################
http://dbus.freedesktop.org/releases/dbus/
2)安装tcpdump:
cd /data/codesdev/libpcap/tcpdump-4.6.1
./configure&&make && make install
在centos6.4上安装后如下:
tcpdump --version
tcpdump version 4.6.1
libpcap version 1.6.1
OpenSSL 1.0.1e-fips 11 Feb 2013
二:通过tcpdump抓取HTTP包的方法,实践Ok:
tcpdump -XvvennSs 0 -i eth0 tcp[20:2]=0x4745 or tcp[20:2]=0x4854
0x4745 为"GET"前两个字母"GE"
0x4854 为"HTTP"前两个字母"HT"
来自:http://zhumeng8337797.blog.163.com/blog/static/100768914201291110503529/
经过实践是可以的,特别是对接口的调试这一块很是有用,特记录如下:
解释:
0x4745 为"GET"前两个字母"GE"
0x4854 为"HTTP"前两个字母"HT"
实践如下:
[root@localhost ~]# tcpdump -XvvennSs 0 -i eth0 tcp[20:2]=0x4745 or tcp[20:2]=0x4854 -w /tmp/capture.pcap
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
8 packets captured
8 packets received by filter
0 packets dropped by kernel
[root@localhost ~]# sz /tmp/capture.pcap
[/codes]
三:通过网卡eth1来监听端口80发出去的host包到192.168.109.8的报文:
TcpDump位置: /usr/local/sbin/tcpdump
(0)最常用的:
(1)捕获队列的Http请求,不知道是哪个网卡于是得:-i any,根据端口和IP进行捕获:
curl "http://198.168.109.*:1218?charset=utf8&name=playRecord&opt=get",也就是目标是:198.168.109.*
生成如下捕获的tcpdump命令,经测试捕获是Ok的且可以用wireshark打开并查看到http的包:
如监控队列:
(2)加上源地址IP进行捕获:
所有包都截获后sz下来,并用Windows下的wireshark界面进行过滤查看http的包:
实践完全Ok,用wireshark能看到,并能导出:
wireshark界面使用备案Url:http://www.jackxiang.com/post/6262/
四:抓取发往某个指定IP的http get包数据指定文件进行输出package,这个也是下载到Windows下用wireshark界面过滤查看,实践用wireshark能看到:
实践如下:
[root@localhost ~]# tcpdump -XvvennSs 0 -i eth0 port 80 and dst host "192.168.109.8" and tcp[20:2]=0x4745 or tcp[20:2]=0x4854 -w /tmp/capture.pcap
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
Got 4
实践用wireshark打开能看到这些ip的http,实践Ok。
五:如何添加编译好的Tcpdump到到环境变量PATH中的方法:
http://www.jackxiang.com/post/1792/
阅读全文
外包把代码放到我们的测试机上,有可能出现这样那样的调用问题,尽管前面说过要注意host配置的问题并记录,但是往往出现在上到测试机时,忘记了,于是用下tcpdump来抓包,可以实现有效的对其跨系统的接口进行跟踪,并找到问题之所在。
零:使用,方法一:
vi /root/.bashrc
生效:
source /root/.bashrc
方法二(优点这个导出只是传的参数以&符号分割,而返回则全是body里的内容,相当的适合用作接口调试参数,用curl来进行组装访问。):
参考其优点细说在:http://jackxiang.com/post/7344/
特别说明:
tcpdump命令默认捕获包总长度是96字节,如图所示,我们只要在抓包命令里加一个参数 -s 0 即可捕获完整数据的数据包。
/usr/local/sbin/tcpdump -i any -p -s 0 -w /tmp/capture.pcap
一:安装
官网:http://www.tcpdump.org
下载两个包,注意配套,我的是:
http://www.tcpdump.org/release/libpcap-1.4.0.tar.gz
http://www.tcpdump.org/release/tcpdump-4.3.0.tar.gz
Add Time:2014-01-27,上面旧版本没问题,新的有问题:
wget http://www.tcpdump.org/release/tcpdump-4.5.1.tar.gz
wget http://www.tcpdump.org/release/libpcap-1.5.3.tar.gz
1 下载了libpcap-1.5.2.tar.gz。
2 tar -vxf libpcap-1.5.2.tar.gz
3 ./configure
4 make 发生错误。
1)安装:libpcap
cd /data/codesdev/libpcap/libpcap-1.6.1
./configure&&make && make install
理论上一次能过,但是往往会出现新的问题,如下:
[root@master libpcap-1.5.2]# make
gcc -fpic -I. -I/usr/include/dbus-1.0 -I/usr/lib64/dbus-1.0/include -DHAVE_CONFIG_H -D_U_="__attribute__((unused))" -g -O2 -c ./pcap-dbus.c
./pcap-dbus.c: In function ‘dbus_write’:
./pcap-dbus.c:111: 错误:‘DBUS_ERROR_INIT’ 未声明 (在此函数内第一次使用)
./pcap-dbus.c:111: 错误:(即使在一个函数内多次出现,每个未声明的标识符在其
./pcap-dbus.c:111: 错误:所在的函数内只报告一次。)
./pcap-dbus.c: In function ‘dbus_activate’:
./pcap-dbus.c:165: 错误:‘DBUS_ERROR_INIT’ 未声明 (在此函数内第一次使用)
make: *** [pcap-dbus.o] 错误 1
按装dbus:
http://www.freedesktop.org/wiki/Software/dbus/
问题答案未实践来自:http://bbs.csdn.net/topics/390693013
######################我的情况如下######################
cc -fpic -I. -I/usr/include/dbus-1.0 -I/usr/lib64/dbus-1.0/include -DHAVE_CONFIG_H -D_U_="__attribute__((unused))" -g -O2 -c ./pcap-linux.c
gcc -fpic -I. -I/usr/include/dbus-1.0 -I/usr/lib64/dbus-1.0/include -DHAVE_CONFIG_H -D_U_="__attribute__((unused))" -g -O2 -c ./pcap-usb-linux.c
gcc -fpic -I. -I/usr/include/dbus-1.0 -I/usr/lib64/dbus-1.0/include -DHAVE_CONFIG_H -D_U_="__attribute__((unused))" -g -O2 -c ./pcap-dbus.c
./pcap-dbus.c: In function ‘dbus_write’:
./pcap-dbus.c:111: error: ‘DBUS_ERROR_INIT’ undeclared (first use in this function)
./pcap-dbus.c:111: error: (Each undeclared identifier is reported only once
./pcap-dbus.c:111: error: for each function it appears in.)
./pcap-dbus.c: In function ‘dbus_activate’:
./pcap-dbus.c:165: error: ‘DBUS_ERROR_INIT’ undeclared (first use in this function)
make: *** [pcap-dbus.o] Error 1
#########################################################################
http://dbus.freedesktop.org/releases/dbus/
2)安装tcpdump:
cd /data/codesdev/libpcap/tcpdump-4.6.1
./configure&&make && make install
在centos6.4上安装后如下:
tcpdump --version
tcpdump version 4.6.1
libpcap version 1.6.1
OpenSSL 1.0.1e-fips 11 Feb 2013
二:通过tcpdump抓取HTTP包的方法,实践Ok:
tcpdump -XvvennSs 0 -i eth0 tcp[20:2]=0x4745 or tcp[20:2]=0x4854
0x4745 为"GET"前两个字母"GE"
0x4854 为"HTTP"前两个字母"HT"
来自:http://zhumeng8337797.blog.163.com/blog/static/100768914201291110503529/
经过实践是可以的,特别是对接口的调试这一块很是有用,特记录如下:
解释:
0x4745 为"GET"前两个字母"GE"
0x4854 为"HTTP"前两个字母"HT"
实践如下:
[root@localhost ~]# tcpdump -XvvennSs 0 -i eth0 tcp[20:2]=0x4745 or tcp[20:2]=0x4854 -w /tmp/capture.pcap
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
8 packets captured
8 packets received by filter
0 packets dropped by kernel
[root@localhost ~]# sz /tmp/capture.pcap
[/codes]
三:通过网卡eth1来监听端口80发出去的host包到192.168.109.8的报文:
TcpDump位置: /usr/local/sbin/tcpdump
(0)最常用的:
(1)捕获队列的Http请求,不知道是哪个网卡于是得:-i any,根据端口和IP进行捕获:
curl "http://198.168.109.*:1218?charset=utf8&name=playRecord&opt=get",也就是目标是:198.168.109.*
生成如下捕获的tcpdump命令,经测试捕获是Ok的且可以用wireshark打开并查看到http的包:
如监控队列:
(2)加上源地址IP进行捕获:
所有包都截获后sz下来,并用Windows下的wireshark界面进行过滤查看http的包:
实践完全Ok,用wireshark能看到,并能导出:
wireshark界面使用备案Url:http://www.jackxiang.com/post/6262/
四:抓取发往某个指定IP的http get包数据指定文件进行输出package,这个也是下载到Windows下用wireshark界面过滤查看,实践用wireshark能看到:
实践如下:
[root@localhost ~]# tcpdump -XvvennSs 0 -i eth0 port 80 and dst host "192.168.109.8" and tcp[20:2]=0x4745 or tcp[20:2]=0x4854 -w /tmp/capture.pcap
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
Got 4
实践用wireshark打开能看到这些ip的http,实践Ok。
五:如何添加编译好的Tcpdump到到环境变量PATH中的方法:
http://www.jackxiang.com/post/1792/
阅读全文
http://www.centos.bz/2012/12/openresty-nginx-block-cc-attack-deploy/
Linux系统防CC攻击自动拉黑IP增强版Shell脚本:http://zhangge.net/4649.html
阅读全文
Linux系统防CC攻击自动拉黑IP增强版Shell脚本:http://zhangge.net/4649.html
阅读全文
[tab设置]更改Zend Studio/Eclipse的制表Tab缩进为4个空格缩进,荐用空格取代tab,一般取4个空格,这样代码就美观多了。
Php/Js/Shell/Go jackxiang 2013-5-28 10:29
背景:缩进使用4个空格,而不是 tab。这是PHP编程规范手册中的一句话。
今天重装了一下Zend Studio,在编码时发现回车缩进是tab制表符,颇为不爽,记得很久很久以前哥写代码是不缩进的,后来经老师提醒,改用tab缩进,一直这样编码了很长时间。后来看到一篇介绍代码格式的文章才知道各类文本编辑器对于tab制表符的长度规定不一样,这就导致同样缩进的代码在不同系统或者编辑器上缩进长短不一,影响代码风格的一致性。所以推荐用空格取代tab,一般取4个空格,这样代码就美观多了。
实践Ok如下:
在编辑器里,窗口->首选项->PHP->code style->formatter->Edit->Indentation->General settings Tab size: 4.
参考来自:http://wangye.org/blog/archives/541/
==========================================================================================
editplus中tab转换为空格:
缩进使用4个空格,而不是 tab。这是PHP编程规范手册中的一句话。
之所以这样,是因为tab在不同的编辑器代表的空格是不一样的,为了排版不出现混乱,规范中建议直接使用空格。
但是直接用空格的话,我们在写代码的时候经常会需要缩进,不用TAB的话工作量是巨大的。
其实,我们完全可以用EditPlus解决这个问题。
写代码的时候放心去用TAB,写完代码后,用鼠标选择全部代码,右击->format(格式)->tabs to spaces(制表符转为空格),这样就可以把所有的tab改为spaces了。
实践Ok如下:
右键,格式,制表符转为空格。
来自:http://hi.baidu.com/amenmen/item/e7c9588eca8f48d65f0ec120
=========================================================================================
Notepad++
设置->首选项->语言->右下角,以空格取代打勾。
来自:http://bbs.phpchina.com/thread-220762-1-1.html
=========================================================================================
在.vimrc中添加以下代码后,重启vim即可实现按TAB产生4个空格:
set ts=4 (注:ts是tabstop的缩写,设TAB宽4个空格)
set expandtab
对于已保存的文件,可以使用下面的方法进行空格和TAB的替换:
TAB替换为空格:
:set ts=4
:set expandtab
:%retab!
空格替换为TAB:
:set ts=4
:set noexpandtab
:%retab!
加!是用于处理非空白字符之后的TAB,即所有的TAB,若不加!,则只处理行首的TAB。
在.vimrc文件中输入如下文本:
set tabstop=4
set softtabstop=4
set shiftwidth=4
set noexpandtab
set nu
set autoindent
set cindent
其中:Tabstop:表示一个 tab 显示出来是多少个空格的长度,默认 8。
Softtabstop:表示在编辑模式的时候按退格键的时候退回缩进的长度,当使用 expandtab 时特别有用。
Shiftwidth:表示每一级缩进的长度,一般设置成跟 softtabstop 一样。 当设置成 expandtab 时,缩进用空格来表示noexpandtab 则是用制表符表示一个缩进。
Nu:表示显示行号。
Autoindent:表示自动缩进。
Cindent:是特别针对C语言自动缩进。
来自:http://blog.163.com/panda_sha/blog/static/478281962011616124316/
==========================================================================================
在eclipse中设置tab的长度:
在eclipse中设置tab size的地方有多个
1:window——preference——General——Editor——Text Editor设置页面:Display Tab Width
2:window——preference——Java——Code Style——Formatter设置页面,Edit,在弹出的Editor profile窗口中,Indentation卡片,设置Indentation Size和Tab Size。
3:如果安装了Myeclipse,那么在window——preference——Myeclipse——Editor——Common Editor Preference中Apperance卡片,设置Tab Size。
来自:http://taoistwar.iteye.com/blog/369956
今天重装了一下Zend Studio,在编码时发现回车缩进是tab制表符,颇为不爽,记得很久很久以前哥写代码是不缩进的,后来经老师提醒,改用tab缩进,一直这样编码了很长时间。后来看到一篇介绍代码格式的文章才知道各类文本编辑器对于tab制表符的长度规定不一样,这就导致同样缩进的代码在不同系统或者编辑器上缩进长短不一,影响代码风格的一致性。所以推荐用空格取代tab,一般取4个空格,这样代码就美观多了。
实践Ok如下:
在编辑器里,窗口->首选项->PHP->code style->formatter->Edit->Indentation->General settings Tab size: 4.
参考来自:http://wangye.org/blog/archives/541/
==========================================================================================
editplus中tab转换为空格:
缩进使用4个空格,而不是 tab。这是PHP编程规范手册中的一句话。
之所以这样,是因为tab在不同的编辑器代表的空格是不一样的,为了排版不出现混乱,规范中建议直接使用空格。
但是直接用空格的话,我们在写代码的时候经常会需要缩进,不用TAB的话工作量是巨大的。
其实,我们完全可以用EditPlus解决这个问题。
写代码的时候放心去用TAB,写完代码后,用鼠标选择全部代码,右击->format(格式)->tabs to spaces(制表符转为空格),这样就可以把所有的tab改为spaces了。
实践Ok如下:
右键,格式,制表符转为空格。
来自:http://hi.baidu.com/amenmen/item/e7c9588eca8f48d65f0ec120
=========================================================================================
Notepad++
设置->首选项->语言->右下角,以空格取代打勾。
来自:http://bbs.phpchina.com/thread-220762-1-1.html
=========================================================================================
在.vimrc中添加以下代码后,重启vim即可实现按TAB产生4个空格:
set ts=4 (注:ts是tabstop的缩写,设TAB宽4个空格)
set expandtab
对于已保存的文件,可以使用下面的方法进行空格和TAB的替换:
TAB替换为空格:
:set ts=4
:set expandtab
:%retab!
空格替换为TAB:
:set ts=4
:set noexpandtab
:%retab!
加!是用于处理非空白字符之后的TAB,即所有的TAB,若不加!,则只处理行首的TAB。
在.vimrc文件中输入如下文本:
set tabstop=4
set softtabstop=4
set shiftwidth=4
set noexpandtab
set nu
set autoindent
set cindent
其中:Tabstop:表示一个 tab 显示出来是多少个空格的长度,默认 8。
Softtabstop:表示在编辑模式的时候按退格键的时候退回缩进的长度,当使用 expandtab 时特别有用。
Shiftwidth:表示每一级缩进的长度,一般设置成跟 softtabstop 一样。 当设置成 expandtab 时,缩进用空格来表示noexpandtab 则是用制表符表示一个缩进。
Nu:表示显示行号。
Autoindent:表示自动缩进。
Cindent:是特别针对C语言自动缩进。
来自:http://blog.163.com/panda_sha/blog/static/478281962011616124316/
==========================================================================================
在eclipse中设置tab的长度:
在eclipse中设置tab size的地方有多个
1:window——preference——General——Editor——Text Editor设置页面:Display Tab Width
2:window——preference——Java——Code Style——Formatter设置页面,Edit,在弹出的Editor profile窗口中,Indentation卡片,设置Indentation Size和Tab Size。
3:如果安装了Myeclipse,那么在window——preference——Myeclipse——Editor——Common Editor Preference中Apperance卡片,设置Tab Size。
来自:http://taoistwar.iteye.com/blog/369956
http://www.csdn.net/article/2013-05-22/2815382-The-One-Person-Product
PHP的pthreads扩展:真正的PHP多线程(绝非fork或者用http再开进程)。
Php/Js/Shell/Go jackxiang 2013-5-23 09:50
背景:很多PHPer想PHP也像Java / c++ 一样能支持多线程,于是就有了,在新的版本里加了这样一个扩展,之所以它能行,因为Linux本身就支持,用C扩展一下就可以了,这样用到底成熟不,还是值得时间和对这种应用的需求程度进行检验。
扩展地址:
http://pecl.php.net/package/pthreads
阅读全文
扩展地址:
http://pecl.php.net/package/pthreads
阅读全文
C 语言内存错误检测工具 memwatch
Unix/LinuxC技术 jackxiang 2013-5-22 14:51
MEMWATCH 由 Johan Lindh 编写,是一个开放源代码 C 语言内存错误检测工具。只要在代码中添加一个头文件并在 gcc 语句中定义了 MEMWATCH 之后,您就可以跟踪程序中的内存泄漏和错误了。MEMWATCH 支持 ANSI C,它提供结果日志记录,能检测双重释放(double-free)、错误释放(erroneous free)、没有释放的内存(unfreed memory)、溢出和下溢等等。
使用方法:http://hi.baidu.com/nullzone/item/ff7e60fdeae5c0cc521c262d
更多实践:http://hi.baidu.com/gz_gzhao/item/017262f23a5c7008c7dc4563
像Node这样的脚本型也有内存的泄漏问题:
http://www.oschina.net/translate/tracking-down-memory-leaks-in-node-js-a-node-js-holiday-season
使用方法:http://hi.baidu.com/nullzone/item/ff7e60fdeae5c0cc521c262d
更多实践:http://hi.baidu.com/gz_gzhao/item/017262f23a5c7008c7dc4563
像Node这样的脚本型也有内存的泄漏问题:
http://www.oschina.net/translate/tracking-down-memory-leaks-in-node-js-a-node-js-holiday-season
利用PHP操作Linux消息队列完成进程间通信这qnum最大长度修改。
Php/Js/Shell/Go jackxiang 2013-5-22 10:37
膘叔(19129***) 上午 09:51:54
求科谱:msg_stat_queue中,那个qnum最大只有40,也就是我同时只能最大处理40个队列,能不能再大一点?
维尼熊(380139***) 上午 09:53:19
可以
膘叔(19129***) 上午 09:53:37
怎么调整?
维尼熊(380139***) 上午 09:53:52
/proc/sys/fs/mqueue/msg_max
[root@test ~]# cat /proc/sys/fs/mqueue/msg_max
10
阅读全文
求科谱:msg_stat_queue中,那个qnum最大只有40,也就是我同时只能最大处理40个队列,能不能再大一点?
维尼熊(380139***) 上午 09:53:19
可以
膘叔(19129***) 上午 09:53:37
怎么调整?
维尼熊(380139***) 上午 09:53:52
/proc/sys/fs/mqueue/msg_max
[root@test ~]# cat /proc/sys/fs/mqueue/msg_max
10
阅读全文
像点对点专线的视频服务器没有端口?就是192.168.1.1 和192.168.1.2通讯这种传视频和音频的设备用一根网线直接连起来。
用的什么协议传输视频这块儿是电信找人代工的硬件设备,音频视频传输都有哪些协议?
实时的多数是 rtmp,点对点的局域网 把端口都开放就是了。
TCP&&UDP:1935。
Real Time Messaging Protocol(实时消息传送协议协议)概述 实时消息传送协议是Adobe Systems公司为Flash播放器和服务器之间音频、视频和数据传输开发的私有协议。它有三种变种: 1)工作在TCP之上的明文协议,使用端口1935; 2)RTMPT封装在HTTP请求之中,可穿越防火墙; 3)RTMPS类似RTMPT,但使用的是HTTPS连接; 介绍: RTMP协议是被Flash用于对象,视频,音频的传输.该协议建立在TCP协议或者轮询HTTP协议之上. RTMP协议就像一个用来装数据包的容器,这些数据可以是AMF格式的数据,也可以是FLV中的视/音频数据. 一个单一的连接可以通过不同的通道传输多路网络流.这些通道中的包都是按照固定大小的包传输的.
RTMP通讯协议及端口范围
TCP、UDP端口:1935
1.哪些软件可支持下载基于rtmp协议的在线视频呢?
2.顺便问一下,rtmp与http两种协议到底有何不同?
1.唯影视频下载器支持下载使用HTTP、RTMP、RTMPT、RTMPTE等协议的在线视频。
硕鼠最新内测版已经可以支持rtmp协议了,不过首先开放的rtmp解析的站点就cntv和搜狐两家。
还有一个CCTV/CNTV视频下载器(xmlbar),它支持下载CNTV网站中采用rtmp协议以流媒体方式播放的视频。
而比较流行的维棠、迅雷则都不支持rtmp协议。
2.关于rtmp :
这里所说的 rtmp 全称是 real time messaging protocol(实时消息传送协议)。
两种协议HTTP和RTMP,有点点不同:
用HTTP方式:先通过IIS 将FLV下载到本地缓存,然后再通过NetConnection的本地连接来播放这个FLV,这种方法是播放本地的视频,并不是播放服务器的视频。因此在本地缓存里可以找到这个FLV。其优点就是服务器下载完这个FLV,服务器就没有消耗了,节省服务器消耗。其缺点就是FLV会缓存在客户端,对FLV的保密性不好。
用RTMP方式:通过NetConnection连接到FMS/Red5服务器,并实时播放服务器的FLV文件,这种方式可以任意选择视频播放点(SEEK()),并不象HTTP方式需要缓存完整个FLV文件到本地才可以任意选择播放点,其优点就是在本地缓存里是找不到这个FLV文件的。其优点就是FLV不会缓存在客户端,FLV的保密性好,其缺点就是消耗服务器资源,连接始终是实时的。
一句话,HTTP方式是本地播放,RTMP方式是服务器实时播放,因需而定。
Flash RTMP流媒体协议:http://www.cnblogs.com/yjmyzz/archive/2010/03/16/1687192.html
Real Time Messaging Protocol(实时消息传送协议协议)是Adobe Systems公司为Flash播放器和服务器之间音频、视频和数据传输开发的私有协议。
具体使用RTMP的AS代码大概如下:
var videoInstance:Video = your_video_instance;
var nc:NetConnection = new NetConnection();
var connected:Boolean = nc.connect("rtmp://localhost/myapp");
var ns:NetStream = new NetStream(nc);
videoInstance.attachVideo(ns);
ns.play("flvName");
......
RTMP协议详解:http://hi.baidu.com/yore2003/item/a5a198e6029673d3eb34c928
用的什么协议传输视频这块儿是电信找人代工的硬件设备,音频视频传输都有哪些协议?
实时的多数是 rtmp,点对点的局域网 把端口都开放就是了。
TCP&&UDP:1935。
Real Time Messaging Protocol(实时消息传送协议协议)概述 实时消息传送协议是Adobe Systems公司为Flash播放器和服务器之间音频、视频和数据传输开发的私有协议。它有三种变种: 1)工作在TCP之上的明文协议,使用端口1935; 2)RTMPT封装在HTTP请求之中,可穿越防火墙; 3)RTMPS类似RTMPT,但使用的是HTTPS连接; 介绍: RTMP协议是被Flash用于对象,视频,音频的传输.该协议建立在TCP协议或者轮询HTTP协议之上. RTMP协议就像一个用来装数据包的容器,这些数据可以是AMF格式的数据,也可以是FLV中的视/音频数据. 一个单一的连接可以通过不同的通道传输多路网络流.这些通道中的包都是按照固定大小的包传输的.
RTMP通讯协议及端口范围
TCP、UDP端口:1935
1.哪些软件可支持下载基于rtmp协议的在线视频呢?
2.顺便问一下,rtmp与http两种协议到底有何不同?
1.唯影视频下载器支持下载使用HTTP、RTMP、RTMPT、RTMPTE等协议的在线视频。
硕鼠最新内测版已经可以支持rtmp协议了,不过首先开放的rtmp解析的站点就cntv和搜狐两家。
还有一个CCTV/CNTV视频下载器(xmlbar),它支持下载CNTV网站中采用rtmp协议以流媒体方式播放的视频。
而比较流行的维棠、迅雷则都不支持rtmp协议。
2.关于rtmp :
这里所说的 rtmp 全称是 real time messaging protocol(实时消息传送协议)。
两种协议HTTP和RTMP,有点点不同:
用HTTP方式:先通过IIS 将FLV下载到本地缓存,然后再通过NetConnection的本地连接来播放这个FLV,这种方法是播放本地的视频,并不是播放服务器的视频。因此在本地缓存里可以找到这个FLV。其优点就是服务器下载完这个FLV,服务器就没有消耗了,节省服务器消耗。其缺点就是FLV会缓存在客户端,对FLV的保密性不好。
用RTMP方式:通过NetConnection连接到FMS/Red5服务器,并实时播放服务器的FLV文件,这种方式可以任意选择视频播放点(SEEK()),并不象HTTP方式需要缓存完整个FLV文件到本地才可以任意选择播放点,其优点就是在本地缓存里是找不到这个FLV文件的。其优点就是FLV不会缓存在客户端,FLV的保密性好,其缺点就是消耗服务器资源,连接始终是实时的。
一句话,HTTP方式是本地播放,RTMP方式是服务器实时播放,因需而定。
Flash RTMP流媒体协议:http://www.cnblogs.com/yjmyzz/archive/2010/03/16/1687192.html
Real Time Messaging Protocol(实时消息传送协议协议)是Adobe Systems公司为Flash播放器和服务器之间音频、视频和数据传输开发的私有协议。
具体使用RTMP的AS代码大概如下:
var videoInstance:Video = your_video_instance;
var nc:NetConnection = new NetConnection();
var connected:Boolean = nc.connect("rtmp://localhost/myapp");
var ns:NetStream = new NetStream(nc);
videoInstance.attachVideo(ns);
ns.play("flvName");
......
RTMP协议详解:http://hi.baidu.com/yore2003/item/a5a198e6029673d3eb34c928
怎么用BIOS查看CPU温度
Unix/LinuxC技术 jackxiang 2013-5-21 13:33
进入BIOS设置页面之后,可以找到一个叫“Hardware Monitor”或“PC Health”的选项(如笔者的机器是“Power > Hardware Monitor”。
在BIOS看CPU温度、转速和电压
点PC Health Status
CPU Temperature是CPU的温度
CPU Fan是CPU风扇转速
System Fan是机箱风扇转速
1、开机时按DEL进入BIOS设置(显示器上有提示进入办法,但多数是按DEL);
2、选择CPU或硬件信息栏(不同型号BIOS显示的不一样,可以一个个都选一遍)。
3、当能看到“CPU temprature”即为CPU当然温度,有些还能看到CPU风扇、系统风扇等的转速。
在BIOS看CPU温度、转速和电压
点PC Health Status
CPU Temperature是CPU的温度
CPU Fan是CPU风扇转速
System Fan是机箱风扇转速
1、开机时按DEL进入BIOS设置(显示器上有提示进入办法,但多数是按DEL);
2、选择CPU或硬件信息栏(不同型号BIOS显示的不一样,可以一个个都选一遍)。
3、当能看到“CPU temprature”即为CPU当然温度,有些还能看到CPU风扇、系统风扇等的转速。
经常在运行php程序的时候,想知道某个程序到底运行了多久。这样可以查找一些程序运行的效率问题。
一)最近写了一个程序运行的时间计算类,供大家参考:
调用:
二)不用配置Host得到该测试机的访问速度:
如:我想测试一下那个Host为:C:\Windows\System32\drivers\etc\hosts
72.46.130.186 jackxiang.com 的访问速度,用PHP可以用如下代码:
参考来自:http://luzhongxi.blog.163.com/blog/static/200944287201210268201082/
一)最近写了一个程序运行的时间计算类,供大家参考:
调用:
二)不用配置Host得到该测试机的访问速度:
如:我想测试一下那个Host为:C:\Windows\System32\drivers\etc\hosts
72.46.130.186 jackxiang.com 的访问速度,用PHP可以用如下代码:
参考来自:http://luzhongxi.blog.163.com/blog/static/200944287201210268201082/