背景:想在Raspberry Pi下的chrome下播放声音,通过后台播放太慢了,于是想通过html直接调用后立即播放。
<audio src="/style/music.wav" controls="controls" id="play" style="display:none">
Your browser does not support the audio element.
</audio>
audio.play();
事实上Raspberry下的chrome并不能播放mp3和m4a:
________________________________________________________________________________
var audio = document.getElementById('play');
function neworder(){
$.post('/index.php/admin/order/neworder',
{id:112},
function(data,status){
if(data.status==1){
if(one){
one=false;
neworders=data.msg;
}else if(neworders==data.msg){
}else if(neworders<data.msg){
audio.play();
}
}else{}
},'json');
}
setInterval("neworder()",60000)
来自:http://www.ziqiangxuetang.com/jsref/met-audio-play.html
<audio src="/style/music.wav" controls="controls" id="play" style="display:none">
Your browser does not support the audio element.
</audio>
audio.play();
事实上Raspberry下的chrome并不能播放mp3和m4a:
________________________________________________________________________________
var audio = document.getElementById('play');
function neworder(){
$.post('/index.php/admin/order/neworder',
{id:112},
function(data,status){
if(data.status==1){
if(one){
one=false;
neworders=data.msg;
}else if(neworders==data.msg){
}else if(neworders<data.msg){
audio.play();
}
}else{}
},'json');
}
setInterval("neworder()",60000)
来自:http://www.ziqiangxuetang.com/jsref/met-audio-play.html
背景:线上生产环境的系统登录,一般会经过跳板机,而此时为了方便写成脚本里面有自动登录的密码,可能跳板机被攻陷,导致密码泄漏,此时有必要结合跳板机和自己的windows系统把密码和用户名、ip分开。而大一些的公司则是有secretID硬件卡来做这个事情,也主一分钟变一次密码,加上自己设置的前面6位,这样显然更安全,但咱没那钱,于是想了一个土办法简单分开即可。
1)跳板机上:
cat /root/bobwblogin.sh
ssh root@101.200.1.1**
2)windows机器上:
D:\script\bobwbautoenterpwd.vbs
把用户名、ip区分开:
跳板机上执行:
sh /root/bobwblogin.sh
[root@iZ25dcp92ckZ multepoolserver]# sh /root/bobwblogin.sh
root@101.200.1.1**'s password:
密码从步骤2)里面寻找出来即可,在secureCRT里这样操作:
alt+s R, 脚本、执行,找到该路径下的D:\script\bobwbautoenterpwd.vbs文件,即可输入密码进入生产ip。
从而达到了,密码和用户名区分开,不致于windows机或跳板机被拿下后全泄漏了,分开后安全性提高了。
1)跳板机上:
cat /root/bobwblogin.sh
ssh root@101.200.1.1**
2)windows机器上:
D:\script\bobwbautoenterpwd.vbs
把用户名、ip区分开:
跳板机上执行:
sh /root/bobwblogin.sh
[root@iZ25dcp92ckZ multepoolserver]# sh /root/bobwblogin.sh
root@101.200.1.1**'s password:
密码从步骤2)里面寻找出来即可,在secureCRT里这样操作:
alt+s R, 脚本、执行,找到该路径下的D:\script\bobwbautoenterpwd.vbs文件,即可输入密码进入生产ip。
从而达到了,密码和用户名区分开,不致于windows机或跳板机被拿下后全泄漏了,分开后安全性提高了。
[调试关掉]开启OPCache时注意一下关掉这块,否则会等一分钟才生效。
Php/Js/Shell/Go jackxiang 2015-9-22 17:26
背景:有一兄弟用sftp往线下的那个服务器传更改的文件,发现传上去不好使呢,于是重新传,到后来又好了,我当时一看浏览器头,发现也没有啥问题呀,今天我自己搞了一把,发现还真有这个问题,细查了一下,是opcache引起的,默认是60秒。于是我给关了,之前是ea加速,现在新版本的php好像用这个opcache了:
; 2s检查一次文件更新 注意:0是一直检查不是关闭
; 推荐 60
opcache.revalidate_freq=2
————————————————————————
调试先关了,后面没问题再打开:
—————————————————————————
以下是opcache的配置说明:
复制代码
[opcache]
zend_extension = "G:/PHP/php-5.5.6-Win32-VC11-x64/ext/php_opcache.dll"
; Zend Optimizer + 的开关, 关闭时代码不再优化.
opcache.enable=1
; Determines if Zend OPCache is enabled for the CLI version of PHP
opcache.enable_cli=1
; Zend Optimizer + 共享内存的大小, 总共能够存储多少预编译的 PHP 代码(单位:MB)
; 推荐 128
opcache.memory_consumption=64
; Zend Optimizer + 暂存池中字符串的占内存总量.(单位:MB)
; 推荐 8
opcache.interned_strings_buffer=4
; 最大缓存的文件数目 200 到 100000 之间
; 推荐 4000
opcache.max_accelerated_files=2000
; 内存“浪费”达到此值对应的百分比,就会发起一个重启调度.
opcache.max_wasted_percentage=5
; 开启这条指令, Zend Optimizer + 会自动将当前工作目录的名字追加到脚本键上,
; 以此消除同名文件间的键值命名冲突.关闭这条指令会提升性能,
; 但是会对已存在的应用造成破坏.
opcache.use_cwd=0
; 开启文件时间戳验证
opcache.validate_timestamps=1
; 2s检查一次文件更新 注意:0是一直检查不是关闭
; 推荐 60
opcache.revalidate_freq=2
; 允许或禁止在 include_path 中进行文件搜索的优化
;opcache.revalidate_path=0
; 是否保存文件/函数的注释 如果apigen、Doctrine、 ZF2、 PHPUnit需要文件注释
; 推荐 0
opcache.save_comments=1
; 是否加载文件/函数的注释
;opcache.load_comments=1
; 打开快速关闭, 打开这个在PHP Request Shutdown的时候会收内存的速度会提高
; 推荐 1
opcache.fast_shutdown=1
;允许覆盖文件存在(file_exists等)的优化特性。
;opcache.enable_file_override=0
; 定义启动多少个优化过程
;opcache.optimization_level=0xffffffff
; 启用此Hack可以暂时性的解决”can’t redeclare class”错误.
;opcache.inherited_hack=1
; 启用此Hack可以暂时性的解决”can’t redeclare class”错误.
;opcache.dups_fix=0
; 设置不缓存的黑名单
; 不缓存指定目录下cache_开头的PHP文件. /png/www/example.com/public_html/cache/cache_
;opcache.blacklist_filename=
; 通过文件大小屏除大文件的缓存.默认情况下所有的文件都会被缓存.
;opcache.max_file_size=0
; 每 N 次请求检查一次缓存校验.默认值0表示检查被禁用了.
; 由于计算校验值有损性能,这个指令应当紧紧在开发调试的时候开启.
;opcache.consistency_checks=0
; 从缓存不被访问后,等待多久后(单位为秒)调度重启
;opcache.force_restart_timeout=180
; 错误日志文件名.留空表示使用标准错误输出(stderr).
;opcache.error_log=
; 将错误信息写入到服务器(Apache等)日志
;opcache.log_verbosity_level=1
; 内存共享的首选后台.留空则是让系统选择.
;opcache.preferred_memory_model=
; 防止共享内存在脚本执行期间被意外写入, 仅用于内部调试.
;opcache.protect_memory=0
来自:http://www.cnblogs.com/HD/p/4554455.html
opcache.huge_code_pages=1 参数的内在关联:
http://www.laruence.com/2015/10/02/3069.html
; 2s检查一次文件更新 注意:0是一直检查不是关闭
; 推荐 60
opcache.revalidate_freq=2
————————————————————————
调试先关了,后面没问题再打开:
—————————————————————————
以下是opcache的配置说明:
复制代码
[opcache]
zend_extension = "G:/PHP/php-5.5.6-Win32-VC11-x64/ext/php_opcache.dll"
; Zend Optimizer + 的开关, 关闭时代码不再优化.
opcache.enable=1
; Determines if Zend OPCache is enabled for the CLI version of PHP
opcache.enable_cli=1
; Zend Optimizer + 共享内存的大小, 总共能够存储多少预编译的 PHP 代码(单位:MB)
; 推荐 128
opcache.memory_consumption=64
; Zend Optimizer + 暂存池中字符串的占内存总量.(单位:MB)
; 推荐 8
opcache.interned_strings_buffer=4
; 最大缓存的文件数目 200 到 100000 之间
; 推荐 4000
opcache.max_accelerated_files=2000
; 内存“浪费”达到此值对应的百分比,就会发起一个重启调度.
opcache.max_wasted_percentage=5
; 开启这条指令, Zend Optimizer + 会自动将当前工作目录的名字追加到脚本键上,
; 以此消除同名文件间的键值命名冲突.关闭这条指令会提升性能,
; 但是会对已存在的应用造成破坏.
opcache.use_cwd=0
; 开启文件时间戳验证
opcache.validate_timestamps=1
; 2s检查一次文件更新 注意:0是一直检查不是关闭
; 推荐 60
opcache.revalidate_freq=2
; 允许或禁止在 include_path 中进行文件搜索的优化
;opcache.revalidate_path=0
; 是否保存文件/函数的注释 如果apigen、Doctrine、 ZF2、 PHPUnit需要文件注释
; 推荐 0
opcache.save_comments=1
; 是否加载文件/函数的注释
;opcache.load_comments=1
; 打开快速关闭, 打开这个在PHP Request Shutdown的时候会收内存的速度会提高
; 推荐 1
opcache.fast_shutdown=1
;允许覆盖文件存在(file_exists等)的优化特性。
;opcache.enable_file_override=0
; 定义启动多少个优化过程
;opcache.optimization_level=0xffffffff
; 启用此Hack可以暂时性的解决”can’t redeclare class”错误.
;opcache.inherited_hack=1
; 启用此Hack可以暂时性的解决”can’t redeclare class”错误.
;opcache.dups_fix=0
; 设置不缓存的黑名单
; 不缓存指定目录下cache_开头的PHP文件. /png/www/example.com/public_html/cache/cache_
;opcache.blacklist_filename=
; 通过文件大小屏除大文件的缓存.默认情况下所有的文件都会被缓存.
;opcache.max_file_size=0
; 每 N 次请求检查一次缓存校验.默认值0表示检查被禁用了.
; 由于计算校验值有损性能,这个指令应当紧紧在开发调试的时候开启.
;opcache.consistency_checks=0
; 从缓存不被访问后,等待多久后(单位为秒)调度重启
;opcache.force_restart_timeout=180
; 错误日志文件名.留空表示使用标准错误输出(stderr).
;opcache.error_log=
; 将错误信息写入到服务器(Apache等)日志
;opcache.log_verbosity_level=1
; 内存共享的首选后台.留空则是让系统选择.
;opcache.preferred_memory_model=
; 防止共享内存在脚本执行期间被意外写入, 仅用于内部调试.
;opcache.protect_memory=0
来自:http://www.cnblogs.com/HD/p/4554455.html
opcache.huge_code_pages=1 参数的内在关联:
http://www.laruence.com/2015/10/02/3069.html
刘强东谈当下多疯狂:估值两亿美金的二手车应用交易量只有两辆!
我给大家讲一个真实故事,去年年底有个互联网公司业务模式发生变化,以前老的业务不想做了,老板不想开除这些兄弟们,要赔偿一笔钱,跟30多个兄弟们商量说,兄弟们,你们出去创业吧,我给你们投150万人民币。这帮兄弟真就信了,拿了150万人民币去创业了。
到今年3月份见面,本来以为这些兄弟和公司没关系了,从此算是解套了,结果3月份兄弟们告诉他,已经拿到了A轮500万美金的投资,他之前投的150万占了70%的股,最近B轮融资追过来,估值2个亿美金!
原来兄弟们在手机上做了个卖二手车的APP,我问卖了几辆车,他告诉我最多只卖了两辆车,还是员工自己买的。
......
任何一种互联网商业模式,如果不能够降低行业的交易成本,不能够提升行业交易效率的话,那么最后注定会失败的。
________________________________________________________________________________________
本文是京东CEO刘强东近日在京东内部的一场分享。在演讲中,刘强东透露有的估值两亿美元的二手车APP公司,其实交易量少得可怜,“只有两辆!还是员工自己买的”。而东哥也认为,当下互联网泡沫已到了一个顶峰,“在私募市场,估值过10亿美金的企业,中国已经超过50家企业”,疯狂的尽头同时也意味着行业到了谷底。
文 | 刘强东
京东涉足电商应该算是互联网行业里面比较晚的。2004年,中国互联网电商阵营已经很庞大,那时当当拿到C轮融资,卓越卖给了亚马逊,易迅、淘宝等公司都已经成立。
此前我们做了六年传统商业,带着对传统商业的思考进入了互联网。做了12年,我发现互联网并不是和传统行业无关,传统商业的价值和经济规律完全适用于互联网。
只卖了两辆车的二手车APP,居然估值两亿美金
这段时间中国经济有下行压力,再加上最近几年互联网很热门,大量的传统企业老板纷纷找我合作,尤其是我们投资了永辉超市之后,有一大堆的超市找我们,希望能跟京东合作,他们说一定要和互联网有关系。
我很好奇为什么一定要和互联网有关系?有个中欧的校友跟我说了实话,他们感觉跟互联网接上关系,连猪都可以飞起来。
互联网领域有个很普遍的说法,风来了,猪都会飞。我认为如果你是一头猪的话,就两种选择。
第一个选择你使劲吃,使劲睡,抓紧最后的日子,享享福得了。
第二条路,你就每天少吃,多走路,锻炼身体,把自己弄瘦一点儿,让养你的人晚杀你几天,你干嘛非要飞起来?猪飞起来有什么结果?你是头猪,飞到天上去,是疯狂了十几秒,但摔下来死得更快。
我给大家讲一个真实故事,去年年底有个互联网公司业务模式发生变化,以前老的业务不想做了,老板不想开除这些兄弟们,要赔偿一笔钱,跟30多个兄弟们商量说,兄弟们,你们出去创业吧,我给你们投150万人民币。这帮兄弟真就信了,拿了150万人民币去创业了。
到今年3月份见面,本来以为这些兄弟和公司没关系了,从此算是解套了,结果3月份兄弟们告诉他,已经拿到了A轮500万美金的投资,他之前投的150万占了70%的股,最近B轮融资追过来,估值2个亿美金!
原来兄弟们在手机上做了个卖二手车的APP,我问卖了几辆车,他告诉我最多只卖了两辆车,还是员工自己买的。
估值超过10亿美金,如果不能提升行业交易效率,然并卵
十二年以来,我在互联网经历过三次行业谷底,最近一年正在经历第三次行业谷底。整个中国互联网拿到5000万美金融资的几十家企业,估值超过10亿美金,到今天没有一家上市的,但在私募市场,估值过10亿美金的企业,中国已经超过50家企业。我认为,任何时候,行业一旦疯狂的时候就会出问题。
互联网没有违背经济规律,我们看到中国互联网行业发展到今天也就不到10家被记住。任何一个行业只要存在三家以上的巨头,这个行业都不健康,全世界互联网都是这样,全世界互联网第一名占了80%的利润。
其他互联网企业死掉了是什么原因?我们也琢磨了很长时间。最后结论就是任何一种商业模式都要符合传统经济规律,所以我们对互联网的看法,总结就是任何一种互联网商业模式,如果不能够降低行业的交易成本,不能够提升行业交易效率的话,那么最后注定会失败的。
到今天中国所有的互联网企业,能够连续五年市值超过50亿美金,大概只有3家。如果能够连续五年市值过2亿美金以上的规模,也就十来家。如果把他们视为成功者的话,今天所有活下来的互联网企业,都是给行业带来成本的下降和效率的提升。电商就是能带来便利,这种便利的背后,是交易成本的下降。是消费者对此付出更少的时间。
我给大家讲一个真实故事,去年年底有个互联网公司业务模式发生变化,以前老的业务不想做了,老板不想开除这些兄弟们,要赔偿一笔钱,跟30多个兄弟们商量说,兄弟们,你们出去创业吧,我给你们投150万人民币。这帮兄弟真就信了,拿了150万人民币去创业了。
到今年3月份见面,本来以为这些兄弟和公司没关系了,从此算是解套了,结果3月份兄弟们告诉他,已经拿到了A轮500万美金的投资,他之前投的150万占了70%的股,最近B轮融资追过来,估值2个亿美金!
原来兄弟们在手机上做了个卖二手车的APP,我问卖了几辆车,他告诉我最多只卖了两辆车,还是员工自己买的。
......
任何一种互联网商业模式,如果不能够降低行业的交易成本,不能够提升行业交易效率的话,那么最后注定会失败的。
________________________________________________________________________________________
本文是京东CEO刘强东近日在京东内部的一场分享。在演讲中,刘强东透露有的估值两亿美元的二手车APP公司,其实交易量少得可怜,“只有两辆!还是员工自己买的”。而东哥也认为,当下互联网泡沫已到了一个顶峰,“在私募市场,估值过10亿美金的企业,中国已经超过50家企业”,疯狂的尽头同时也意味着行业到了谷底。
文 | 刘强东
京东涉足电商应该算是互联网行业里面比较晚的。2004年,中国互联网电商阵营已经很庞大,那时当当拿到C轮融资,卓越卖给了亚马逊,易迅、淘宝等公司都已经成立。
此前我们做了六年传统商业,带着对传统商业的思考进入了互联网。做了12年,我发现互联网并不是和传统行业无关,传统商业的价值和经济规律完全适用于互联网。
只卖了两辆车的二手车APP,居然估值两亿美金
这段时间中国经济有下行压力,再加上最近几年互联网很热门,大量的传统企业老板纷纷找我合作,尤其是我们投资了永辉超市之后,有一大堆的超市找我们,希望能跟京东合作,他们说一定要和互联网有关系。
我很好奇为什么一定要和互联网有关系?有个中欧的校友跟我说了实话,他们感觉跟互联网接上关系,连猪都可以飞起来。
互联网领域有个很普遍的说法,风来了,猪都会飞。我认为如果你是一头猪的话,就两种选择。
第一个选择你使劲吃,使劲睡,抓紧最后的日子,享享福得了。
第二条路,你就每天少吃,多走路,锻炼身体,把自己弄瘦一点儿,让养你的人晚杀你几天,你干嘛非要飞起来?猪飞起来有什么结果?你是头猪,飞到天上去,是疯狂了十几秒,但摔下来死得更快。
我给大家讲一个真实故事,去年年底有个互联网公司业务模式发生变化,以前老的业务不想做了,老板不想开除这些兄弟们,要赔偿一笔钱,跟30多个兄弟们商量说,兄弟们,你们出去创业吧,我给你们投150万人民币。这帮兄弟真就信了,拿了150万人民币去创业了。
到今年3月份见面,本来以为这些兄弟和公司没关系了,从此算是解套了,结果3月份兄弟们告诉他,已经拿到了A轮500万美金的投资,他之前投的150万占了70%的股,最近B轮融资追过来,估值2个亿美金!
原来兄弟们在手机上做了个卖二手车的APP,我问卖了几辆车,他告诉我最多只卖了两辆车,还是员工自己买的。
估值超过10亿美金,如果不能提升行业交易效率,然并卵
十二年以来,我在互联网经历过三次行业谷底,最近一年正在经历第三次行业谷底。整个中国互联网拿到5000万美金融资的几十家企业,估值超过10亿美金,到今天没有一家上市的,但在私募市场,估值过10亿美金的企业,中国已经超过50家企业。我认为,任何时候,行业一旦疯狂的时候就会出问题。
互联网没有违背经济规律,我们看到中国互联网行业发展到今天也就不到10家被记住。任何一个行业只要存在三家以上的巨头,这个行业都不健康,全世界互联网都是这样,全世界互联网第一名占了80%的利润。
其他互联网企业死掉了是什么原因?我们也琢磨了很长时间。最后结论就是任何一种商业模式都要符合传统经济规律,所以我们对互联网的看法,总结就是任何一种互联网商业模式,如果不能够降低行业的交易成本,不能够提升行业交易效率的话,那么最后注定会失败的。
到今天中国所有的互联网企业,能够连续五年市值超过50亿美金,大概只有3家。如果能够连续五年市值过2亿美金以上的规模,也就十来家。如果把他们视为成功者的话,今天所有活下来的互联网企业,都是给行业带来成本的下降和效率的提升。电商就是能带来便利,这种便利的背后,是交易成本的下降。是消费者对此付出更少的时间。
背景:听说在微信上搞个服务号,怎么调试呢?微信上也是web做的服务号手机网站,在PC端有Firebug和chrome的F12调试,而用苹果的web端调试则是用苹果手机连接上苹果电脑,打开safari进行调试,相当有效果。
我们知道在 Mac/PC 上的浏览器都有 Web 检查器这类的工具(如最著名的 Firebug)对前端开发进行调试,而在 iPhone/iPad 由于限于屏幕的大小和触摸屏的使用习惯,直接对网页调试非常不方便,所以一直没有 Web 检查器这一类工具。
但是 iOS 6 的发布解决了这个问题。
iOS 6 给 Safari 带来了远程的 Web 检查器工具(Remote Web Inspector),你可以通过模拟器或者真实的设备(通过 USB 连上 Mac)进行调试。下面我讲讲详细的调试过程:
1. 要进行远程调试,首先要打开开启 iPhone/iPad 上的 Safari 的远程调试功能,“通过 设置 > Safari > 高级”开启:
2. 然后打开 Safari,开启你要调试的网页,当然原生应用中通过 WebView 开启的网页也是可以调试的。
3. 最后把 iPhone 或者 iPad 通过数据线连上 Mac 电脑,打开桌面版的 Safari(目前 iOS 6 的 Safari 远程调试只支持通过 Mac 上的桌面版的 Safari 进行,Safari for Windows 目前还没有此项功能),点击开发菜单,选择你调试的 iPhone/iPad 的设备名,选择调试的网页。
4. 最后就是调用桌面版的 Safari 的 Web 检查器对 iPhone/iPad 上的 Safari 应用进行调试:
这个调试过程和我们平常在 Mac/PC 上调试基本一样,比如可以对 HTML 和 CSS 做些实时的改动,查看修改后的效果。查看 cookie,本地存储,session 等一些数据。查看 WebApp 的性能,网络请求等,也可以查看所有错误和警告信息对程序进行修正。
当然我们可以通过它来调试 Javascript,设置断点,定义未捕获的意外等。也可以访问 Console,直接执行 Javascript 代码。
另外它还支持触摸检查(Touch to inspect):激活检查器上的手型图标,就可以通过在 iPhone/iPad 上触摸,就能立即找到检查器对应的 DOM 元素。
来自:http://www.leiphone.com/news/201406/ios-safari-remote-debugging.html
我们知道在 Mac/PC 上的浏览器都有 Web 检查器这类的工具(如最著名的 Firebug)对前端开发进行调试,而在 iPhone/iPad 由于限于屏幕的大小和触摸屏的使用习惯,直接对网页调试非常不方便,所以一直没有 Web 检查器这一类工具。
但是 iOS 6 的发布解决了这个问题。
iOS 6 给 Safari 带来了远程的 Web 检查器工具(Remote Web Inspector),你可以通过模拟器或者真实的设备(通过 USB 连上 Mac)进行调试。下面我讲讲详细的调试过程:
1. 要进行远程调试,首先要打开开启 iPhone/iPad 上的 Safari 的远程调试功能,“通过 设置 > Safari > 高级”开启:
2. 然后打开 Safari,开启你要调试的网页,当然原生应用中通过 WebView 开启的网页也是可以调试的。
3. 最后把 iPhone 或者 iPad 通过数据线连上 Mac 电脑,打开桌面版的 Safari(目前 iOS 6 的 Safari 远程调试只支持通过 Mac 上的桌面版的 Safari 进行,Safari for Windows 目前还没有此项功能),点击开发菜单,选择你调试的 iPhone/iPad 的设备名,选择调试的网页。
4. 最后就是调用桌面版的 Safari 的 Web 检查器对 iPhone/iPad 上的 Safari 应用进行调试:
这个调试过程和我们平常在 Mac/PC 上调试基本一样,比如可以对 HTML 和 CSS 做些实时的改动,查看修改后的效果。查看 cookie,本地存储,session 等一些数据。查看 WebApp 的性能,网络请求等,也可以查看所有错误和警告信息对程序进行修正。
当然我们可以通过它来调试 Javascript,设置断点,定义未捕获的意外等。也可以访问 Console,直接执行 Javascript 代码。
另外它还支持触摸检查(Touch to inspect):激活检查器上的手型图标,就可以通过在 iPhone/iPad 上触摸,就能立即找到检查器对应的 DOM 元素。
来自:http://www.leiphone.com/news/201406/ios-safari-remote-debugging.html
PHP不如C++ 吗?被swoole坑哭的PHP程序员。
Php/Js/Shell/Go jackxiang 2015-9-17 14:26
昨天和一个前同事聊天,各种吐槽PHP,吐槽Swoole,他认为PHP到处是坑,PHP局限很大。PHP+Swoole不适合做高并发服务器,C+Swoole才是最好的方案。C++有各种数据结构,C++可以开线程,C++可以共享对象。看来有必要好好得说明一下了。
PHP不如C++ 吗?
PHP比C/C++或Java少了什么?多线程,多线程,多线程……
是的。PHP比C/C++、Java少了多了多线程。PHP只有多进程的方案,所以PHP里的全局变量和对象不是共享的、数据结构也不能跨进程操作、Socket文件描述符不能共享等等。所以PHP有局限?
多线程看似比多进程要强大很多,实际上我可以负责任的告诉你,多线程带来的坑更多。
数据同步问题会让你崩溃的。要么就牺牲性能到处加锁,要么就用地狱难度的无锁并发编程,据我所知目前国内能掌握此项技能的人凤毛麟角。
不要以为加锁就万事大吉了,你会在死锁问题上栽个大跟头。当你的程序逻辑复杂后,锁越来越难控制了,一旦死锁你的程序基本上就完了。
某个线程挂了那所有线程都会退出
反而在看多进程,其实就简单的多了。
配合进程间通信,基本上你可以实现任意的数据共享。比如利用一个进程专门存数据结构和对象,其他进程的数据操作全部投递到此进程来
多进程不需要锁
多进程可以使用共享内存的数据结构实现一些多线程的功能。如Swoole提供的Table、Atomic可以实现数据共享,但成本很低。未来还会加入共享内存队列
所谓PHP限制了Swoole,这完全是无稽之谈。合理利用Swoole提供的Table、Atomic、SendMessage/PipeMessage、Task完全可以实现异步非阻塞的代码逻辑。
C++写出来的程序性能更好?
这完全是盲目的迷信,密集计算的程序C++确实是有优势的。而并发服务器核心是IO,并非大规模密集运算。C++从语言层面来看并没有什么优势。另外C++中的大部分数据结构在PHP中都有对应的实现,实在不行自己写个专门的扩展也能解决之。
高并发的服务器单机能维持10W连接、每秒可处理3-5W笔消息收发。这种性能水准已经可以应用在BAT的核心系统上了。
开发效率快的意义是什么?
这位同事还说PHP开发Server虽然比C++快了,但是追求性能的极致还是要用C++。我要告诉你效率高了究竟意义何在。开发一套好程序不是一 件容易的事情,需要程序员投入大量时间和精力。开发效率提升的意义并不是简单的我可以更少时间完工,而是剩下的时间你可以增加单元测试、修复BUG、提升 用户体验、完善细节、提供配套工具、优化性能、增加关键日志、增加监控报警、增加容灾方案。
被swoole坑哭的PHP程序员:
首先说一下对swoole的理解:披着PHP外衣的C程序。很多PHPer朋友看到swoole提供的强大功能、外界对其的崇拜便跃跃欲试的安装、调 试其demo、编写新功能,然后兴奋的奔走相告。没过几天当你按照自己的理解继续用swoole时,发现代码并没有按照自己的预期运行,然后开始破口大 骂,什么破东西呀,代码跟demo基本一样,为啥运行不通呢?什么狗屁work、task、共享内存、ipcs、异步,各种问题涌现,然后迅速去查官方文 档,发现文档中竟然对这些并没有提及,只是简单的介绍怎么使用,此时几乎对swoole丧失希望。
被swoole坑哭的PHP程序员
遇到的几点问题:
1:关于phper常用的全局变量(global)为什么在onRequest函数中不能使用。
因为swoole是多线程编程,global是不能在多个进程间共享的。例
global $i = 0;
function onRequest() {
echo $i++;
}
如果在swoole中写一个上面的程序,并不会每次访问输出一个递增的数字。如果要实现预期的效果,需要使用swoole_table的相关函数。
2:什么是异步、什么是回高
对于phper来说,对异步、回调的理解估计就是ajax。当看到swoole里面对异步、回调的解释,貌似很简单的样子,就这样在没有任何多线程编辑经验的时候贸然用了swoole,结果被坑的偷偷撸代码好几个通宵来填自己的坑。
3:为什么onReceive收到的数据这么大
客户端发送的多次请求,服务端是可以一次性接收的。并不是客户端发送一次,服务端接收一次
4:自制httpserve
写一个http服务端,然后通过浏览器访问这个自制的服务器,刷新一次浏览器,服务端为什么为接收到两次请求?这个问题估计困饶了好多初次用swoole写httpserver的朋友。因为浏览器会多发一个favicon.ico请求。
原因
出现这种情况的原因其实很简 单,大部分phper都只会php这一种语言,主要用途就是做web,写业务逻辑。很少去了解服务器程序的开发。有一次一个朋友用swoole写了一个简 单的服务端,一个客户端,跑过来问我为什么都启动了却都收不到数据,我简单看了下代码,所有连接确实都成功了,两端都设置了onReceive回调,代码 没问题,看到最后才发现他的服务端、客户端都设置了接到消息的回调函数,但是两端都没有向对方发消息,两端处于僵持状态。然后swoole官方对于这种常 识问题没有给出说明,只是说如何设置回调、如何发消息,如何这样,如何那样。对于有服务端开发经验的同学来说,肯定不会遇到这种问题,swoole文档也 不需要指明需要这样做,因为这是常识。但对于phper来说,指明这一点是非常重要的,因为如上面所说phper是没有这方面认知的,只有服务端开发经验 的程序员有才会有。
swoole的特色:网络通信 框架、异步、多线程。这些特性正是php所不完善的功能(虽然官方提供很多基础函数可以实现这些功能,然后缺少中文文档,很少有人用php来实现这部分功 能),普通的phper也不具备这些特性的基础认知,所以贸然使用swoole难免会遇到一些根本在swoole官方查不到的常识问题。
使用swoole必须要掌握的技能
多线程编程
进程间通信
网络协议TCP/UDP的认知
PHP的各项基本技能
个人学习swoole的经历
在很久之前我也是一个只会 php的程序员,后来一次偶然机会需要用httpsqs,用了一段时间后发现有一些个性的需求,于是就开始看源码。这真是不看不知道,一看吓一 跳,httpsqs只是一层简单的包装,内部是一个Tokyo Cabinet数据库,印象中封装的代码也就一百多行。主要思路就是用C语言的libevent做了一个http服务器,接收请求读写tokyo cabinet数据库,当时按照这种思路做出来的程序确实不少。后来我就突发奇想,既然C语言可以用libevent函数,那PHP肯定也可以用 libevent监听网络,接收请求后读写数据库做队列服务。后来经过查php官方文档,PHP确实提供一系统完整的函数来完成这些功能,甚至多线程的全 套函数都有提供,但中文文档太少,网上也很少搜索到成熟的代码。在逼不得已的情况下,补习了linux-C多线程开发的基本原理,进程间通信的常用方法, 也用来做了一些简单的demo。唯一的感觉就是写一个简单的功能,设计起来还真复杂。就在快要放弃的时候,swoole出现了。swoole所提供的功能 正是php所缺失的功能,简直是太棒了。swoole做为一种网络通信框架,只需要简单的几行设置,一个服务器就搭建起来了,以后就是不断的去完善业务代 码。之前在libevent交流群中得知swoole的设计在c\c++中并不是最好的框架设计,但其亮点就是把基本功能用C封装好,业务功能留给世界上 最好的语言PHP来编写。自此便开始了swoole的填坑之旅。
总结
swoole并不是一个简单的PHP框架,正如swoole官方首页的第一句话“重新定义PHP”,千万不要用旧有php的思想来写swoole代码!swoole重新激活了PHP,php成就了swoole!
PHP不如C++ 吗?
PHP比C/C++或Java少了什么?多线程,多线程,多线程……
是的。PHP比C/C++、Java少了多了多线程。PHP只有多进程的方案,所以PHP里的全局变量和对象不是共享的、数据结构也不能跨进程操作、Socket文件描述符不能共享等等。所以PHP有局限?
多线程看似比多进程要强大很多,实际上我可以负责任的告诉你,多线程带来的坑更多。
数据同步问题会让你崩溃的。要么就牺牲性能到处加锁,要么就用地狱难度的无锁并发编程,据我所知目前国内能掌握此项技能的人凤毛麟角。
不要以为加锁就万事大吉了,你会在死锁问题上栽个大跟头。当你的程序逻辑复杂后,锁越来越难控制了,一旦死锁你的程序基本上就完了。
某个线程挂了那所有线程都会退出
反而在看多进程,其实就简单的多了。
配合进程间通信,基本上你可以实现任意的数据共享。比如利用一个进程专门存数据结构和对象,其他进程的数据操作全部投递到此进程来
多进程不需要锁
多进程可以使用共享内存的数据结构实现一些多线程的功能。如Swoole提供的Table、Atomic可以实现数据共享,但成本很低。未来还会加入共享内存队列
所谓PHP限制了Swoole,这完全是无稽之谈。合理利用Swoole提供的Table、Atomic、SendMessage/PipeMessage、Task完全可以实现异步非阻塞的代码逻辑。
C++写出来的程序性能更好?
这完全是盲目的迷信,密集计算的程序C++确实是有优势的。而并发服务器核心是IO,并非大规模密集运算。C++从语言层面来看并没有什么优势。另外C++中的大部分数据结构在PHP中都有对应的实现,实在不行自己写个专门的扩展也能解决之。
高并发的服务器单机能维持10W连接、每秒可处理3-5W笔消息收发。这种性能水准已经可以应用在BAT的核心系统上了。
开发效率快的意义是什么?
这位同事还说PHP开发Server虽然比C++快了,但是追求性能的极致还是要用C++。我要告诉你效率高了究竟意义何在。开发一套好程序不是一 件容易的事情,需要程序员投入大量时间和精力。开发效率提升的意义并不是简单的我可以更少时间完工,而是剩下的时间你可以增加单元测试、修复BUG、提升 用户体验、完善细节、提供配套工具、优化性能、增加关键日志、增加监控报警、增加容灾方案。
被swoole坑哭的PHP程序员:
首先说一下对swoole的理解:披着PHP外衣的C程序。很多PHPer朋友看到swoole提供的强大功能、外界对其的崇拜便跃跃欲试的安装、调 试其demo、编写新功能,然后兴奋的奔走相告。没过几天当你按照自己的理解继续用swoole时,发现代码并没有按照自己的预期运行,然后开始破口大 骂,什么破东西呀,代码跟demo基本一样,为啥运行不通呢?什么狗屁work、task、共享内存、ipcs、异步,各种问题涌现,然后迅速去查官方文 档,发现文档中竟然对这些并没有提及,只是简单的介绍怎么使用,此时几乎对swoole丧失希望。
被swoole坑哭的PHP程序员
遇到的几点问题:
1:关于phper常用的全局变量(global)为什么在onRequest函数中不能使用。
因为swoole是多线程编程,global是不能在多个进程间共享的。例
global $i = 0;
function onRequest() {
echo $i++;
}
如果在swoole中写一个上面的程序,并不会每次访问输出一个递增的数字。如果要实现预期的效果,需要使用swoole_table的相关函数。
2:什么是异步、什么是回高
对于phper来说,对异步、回调的理解估计就是ajax。当看到swoole里面对异步、回调的解释,貌似很简单的样子,就这样在没有任何多线程编辑经验的时候贸然用了swoole,结果被坑的偷偷撸代码好几个通宵来填自己的坑。
3:为什么onReceive收到的数据这么大
客户端发送的多次请求,服务端是可以一次性接收的。并不是客户端发送一次,服务端接收一次
4:自制httpserve
写一个http服务端,然后通过浏览器访问这个自制的服务器,刷新一次浏览器,服务端为什么为接收到两次请求?这个问题估计困饶了好多初次用swoole写httpserver的朋友。因为浏览器会多发一个favicon.ico请求。
原因
出现这种情况的原因其实很简 单,大部分phper都只会php这一种语言,主要用途就是做web,写业务逻辑。很少去了解服务器程序的开发。有一次一个朋友用swoole写了一个简 单的服务端,一个客户端,跑过来问我为什么都启动了却都收不到数据,我简单看了下代码,所有连接确实都成功了,两端都设置了onReceive回调,代码 没问题,看到最后才发现他的服务端、客户端都设置了接到消息的回调函数,但是两端都没有向对方发消息,两端处于僵持状态。然后swoole官方对于这种常 识问题没有给出说明,只是说如何设置回调、如何发消息,如何这样,如何那样。对于有服务端开发经验的同学来说,肯定不会遇到这种问题,swoole文档也 不需要指明需要这样做,因为这是常识。但对于phper来说,指明这一点是非常重要的,因为如上面所说phper是没有这方面认知的,只有服务端开发经验 的程序员有才会有。
swoole的特色:网络通信 框架、异步、多线程。这些特性正是php所不完善的功能(虽然官方提供很多基础函数可以实现这些功能,然后缺少中文文档,很少有人用php来实现这部分功 能),普通的phper也不具备这些特性的基础认知,所以贸然使用swoole难免会遇到一些根本在swoole官方查不到的常识问题。
使用swoole必须要掌握的技能
多线程编程
进程间通信
网络协议TCP/UDP的认知
PHP的各项基本技能
个人学习swoole的经历
在很久之前我也是一个只会 php的程序员,后来一次偶然机会需要用httpsqs,用了一段时间后发现有一些个性的需求,于是就开始看源码。这真是不看不知道,一看吓一 跳,httpsqs只是一层简单的包装,内部是一个Tokyo Cabinet数据库,印象中封装的代码也就一百多行。主要思路就是用C语言的libevent做了一个http服务器,接收请求读写tokyo cabinet数据库,当时按照这种思路做出来的程序确实不少。后来我就突发奇想,既然C语言可以用libevent函数,那PHP肯定也可以用 libevent监听网络,接收请求后读写数据库做队列服务。后来经过查php官方文档,PHP确实提供一系统完整的函数来完成这些功能,甚至多线程的全 套函数都有提供,但中文文档太少,网上也很少搜索到成熟的代码。在逼不得已的情况下,补习了linux-C多线程开发的基本原理,进程间通信的常用方法, 也用来做了一些简单的demo。唯一的感觉就是写一个简单的功能,设计起来还真复杂。就在快要放弃的时候,swoole出现了。swoole所提供的功能 正是php所缺失的功能,简直是太棒了。swoole做为一种网络通信框架,只需要简单的几行设置,一个服务器就搭建起来了,以后就是不断的去完善业务代 码。之前在libevent交流群中得知swoole的设计在c\c++中并不是最好的框架设计,但其亮点就是把基本功能用C封装好,业务功能留给世界上 最好的语言PHP来编写。自此便开始了swoole的填坑之旅。
总结
swoole并不是一个简单的PHP框架,正如swoole官方首页的第一句话“重新定义PHP”,千万不要用旧有php的思想来写swoole代码!swoole重新激活了PHP,php成就了swoole!
保持简单,保持聪明
这个语言也有它的缺点。只有相对较少的程序员了解Erlang,它也不会百分百与如今互联网公司的代码相匹配。Facebook用Erlang语言开发了他们自己的聊天app,但最终他们还是重新用其他语言进行再次开发,以适配其他基础架构。 “Erlang是我们拥有的一座岛的话,我们很难建造出足够多的船可以停靠到岛上。”Facebook工程副总裁Jay Parikh说。
摘自:http://www.huxiu.com/article/126127/1.html?f=wangzhan
这个语言也有它的缺点。只有相对较少的程序员了解Erlang,它也不会百分百与如今互联网公司的代码相匹配。Facebook用Erlang语言开发了他们自己的聊天app,但最终他们还是重新用其他语言进行再次开发,以适配其他基础架构。 “Erlang是我们拥有的一座岛的话,我们很难建造出足够多的船可以停靠到岛上。”Facebook工程副总裁Jay Parikh说。
摘自:http://www.huxiu.com/article/126127/1.html?f=wangzhan
背景:个人喜欢直接回车,键盘操作,也有用鼠标的:回车搜索。也有没有必要回车的。
一定要注意是有form的表单,即:
<form> </form>
__________________________
我们有时候希望回车键敲在文本框(input element)里来提交表单(form),但有时候又不希望如此。比如搜索行为,希望输入完关键词之后直接按回车键立即提交表单,而有些复杂表单,可能要避免回车键误操作在未完成表单填写的时候就触发了表单提交。
要控制这些行为,不需要借助JS,浏览器已经帮我们做了这些处理,这里总结几条规则:
1. 如果表单里有一个type=”submit”的按钮,回车键生效。
2. 如果表单里只有一个type=”text”的input,不管按钮是什么type,回车键生效。
3. 如果按钮不是用input,而是用button,并且没有加type,IE下默认为type=button,FX默认为type=submit。
4. 其他表单元素如textarea、select不影响,radio checkbox不影响触发规则,但本身在FX下会响应回车键,在IE下不响应。
5. type=”image”的input,效果等同于type=”submit”,不知道为什么会设计这样一种type,不推荐使用,应该用CSS添加背景图合适些。
6.我们在处理表单的页面可以检验他是否点击了按钮来控制下面的程序。if($_POST['submit']){ 如果点击了按钮 程序继续}
实际应用的时候,要让表单响应回车键很容易,保证表单里有个type=”submit”的按钮就行。而当只有一个文本框又不希望响应回车键怎么办 呢?我的方法有点别扭,就是再写一个无意义的文本框,隐藏起来。根据第3条规则,我们在用button的时候,尽量显式声明type以使浏览器表现一致。
通过以上可知只要把type="submit"改成type="button"然后js提交, 在不要有一个type=”text”的input就行了。就不会发生回车跳转。
但实验发现,ie和火狐不一样,火狐的submit按钮有掩藏的(display:block)和显现的都不行,必须全改,但ie只要显现的没有submit就行了。
复制代码
<!DOCTYPE html>
<html>
<head>
<meta charset="gb18030" />
<meta http-equiv="Content-Type" content="text/html; charset=gb18030" />
<title>HTML 5 gb18030编码格式</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" type="text/javascript"></script>
</head>
<body>
<script type="text/javascript">
function doSubmit() {
alert("XXXXXXXXX");
return false;
}
//监听回车
/* $(document).ready(function() {
$(document).keydown(function(e) {
if (e.keyCode == 13) {
alert("xxxxNX");
}
});<input type="submit" value="submit" />
});*/
</script>
<form onsubmit="return doSubmit();" method="post" action="">
<input type="text" />
<input type="button" value="button" />
<input type="text" style="display:none" value="此处的input删掉然后回车按钮就会触发提交" />
</form>
</body>
</html>
复制代码
本文是看了http://yuanyuan7891.iteye.com/blog/567532之后晚上回家实验了总结的。感谢yuanyuan7891的博文的帮助。
一定要注意是有form的表单,即:
<form> </form>
__________________________
我们有时候希望回车键敲在文本框(input element)里来提交表单(form),但有时候又不希望如此。比如搜索行为,希望输入完关键词之后直接按回车键立即提交表单,而有些复杂表单,可能要避免回车键误操作在未完成表单填写的时候就触发了表单提交。
要控制这些行为,不需要借助JS,浏览器已经帮我们做了这些处理,这里总结几条规则:
1. 如果表单里有一个type=”submit”的按钮,回车键生效。
2. 如果表单里只有一个type=”text”的input,不管按钮是什么type,回车键生效。
3. 如果按钮不是用input,而是用button,并且没有加type,IE下默认为type=button,FX默认为type=submit。
4. 其他表单元素如textarea、select不影响,radio checkbox不影响触发规则,但本身在FX下会响应回车键,在IE下不响应。
5. type=”image”的input,效果等同于type=”submit”,不知道为什么会设计这样一种type,不推荐使用,应该用CSS添加背景图合适些。
6.我们在处理表单的页面可以检验他是否点击了按钮来控制下面的程序。if($_POST['submit']){ 如果点击了按钮 程序继续}
实际应用的时候,要让表单响应回车键很容易,保证表单里有个type=”submit”的按钮就行。而当只有一个文本框又不希望响应回车键怎么办 呢?我的方法有点别扭,就是再写一个无意义的文本框,隐藏起来。根据第3条规则,我们在用button的时候,尽量显式声明type以使浏览器表现一致。
通过以上可知只要把type="submit"改成type="button"然后js提交, 在不要有一个type=”text”的input就行了。就不会发生回车跳转。
但实验发现,ie和火狐不一样,火狐的submit按钮有掩藏的(display:block)和显现的都不行,必须全改,但ie只要显现的没有submit就行了。
复制代码
<!DOCTYPE html>
<html>
<head>
<meta charset="gb18030" />
<meta http-equiv="Content-Type" content="text/html; charset=gb18030" />
<title>HTML 5 gb18030编码格式</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" type="text/javascript"></script>
</head>
<body>
<script type="text/javascript">
function doSubmit() {
alert("XXXXXXXXX");
return false;
}
//监听回车
/* $(document).ready(function() {
$(document).keydown(function(e) {
if (e.keyCode == 13) {
alert("xxxxNX");
}
});<input type="submit" value="submit" />
});*/
</script>
<form onsubmit="return doSubmit();" method="post" action="">
<input type="text" />
<input type="button" value="button" />
<input type="text" style="display:none" value="此处的input删掉然后回车按钮就会触发提交" />
</form>
</body>
</html>
复制代码
本文是看了http://yuanyuan7891.iteye.com/blog/567532之后晚上回家实验了总结的。感谢yuanyuan7891的博文的帮助。
C语言读取二进制文件大小
Unix/LinuxC技术 jackxiang 2015-9-16 14:38
背景:如果获取一个二进制文件大小,可能用stat命令,也可能c函数ftell去转一圈,知道大小。
//把文件的位置指针移到文件尾
fseek(fp,OL,SEEK_END);
//获取文件长度;
length=ftell(fp);
printf("该文件的长度为%1d字节\n",length);
[root@iZ25dcp92ckZ multepoolserver]# ./getbinfilesize
binary file ./tianxia2.mp4 size=11827505
//把文件的位置指针移到文件尾
fseek(fp,OL,SEEK_END);
//获取文件长度;
length=ftell(fp);
printf("该文件的长度为%1d字节\n",length);
[root@iZ25dcp92ckZ multepoolserver]# ./getbinfilesize
binary file ./tianxia2.mp4 size=11827505
阿里有卖这玩意,有的是自己运维搞,放这儿备案下:
如何选择你的RDS:
http://help.aliyun.com/knowledge_detail.htm?knowledgeId=5989703
如何快速平稳的迁入RDS:
http://hidba.org/?p=899
http://hidba.org/?p=919
http://hidba.org/?p=929
http://hidba.org/?p=941
如何选择你的RDS:
http://help.aliyun.com/knowledge_detail.htm?knowledgeId=5989703
如何快速平稳的迁入RDS:
http://hidba.org/?p=899
http://hidba.org/?p=919
http://hidba.org/?p=929
http://hidba.org/?p=941
Linux探索之旅之流、管道、重定向,三管齐下
Unix/LinuxC技术 jackxiang 2015-9-14 11:53
背景:关于Linux的流概念,比如在调试C代码时,出错了,或是想捕获输出的错误到同一个文件,这些都要用到流知识,输入,输出,错误分别是:0,1,2,于是有了 >2 >2&1,该文章都有详细解答讲解,写的非常好,写的非常好,难得的好干货,拨云见雾………我已经无力吐槽。
如:
[root@iZ25dcp92ckZ multepoolserver]# cat aaa.txt
cat: aaa.txt: 没有那个文件或目录
[root@iZ25dcp92ckZ multepoolserver]# cat aaa.txt > notexist.txt 2>&1
[root@iZ25dcp92ckZ multepoolserver]# cat notexist.txt
cat: aaa.txt: 没有那个文件或目录
————————————————————————————————————
./multepoolser > echoOut.txt
./tianxia > appleOut.txt 2>&1
————————————————————————————————————————————————————————
内容简介
1、第三部分第二课:流、管道、重定向,三管齐下
2、第三部分第三课预告:监视系统活动,滴水不漏
流、管道、重定向,三管齐下
这一课我们来学一些非常有用的内容,而且相当有意思,而且内容很多,而且有可能颠覆你的三《观》(毕竟三管齐下,不颠覆三观也难)。
今天的标题中的三个名称,听上去就怪怪的。什么流,管道,重定向,都啥玩意啊。不过希望学完这课,大家能够有拨云见雾的感觉。
到目前为止,我们已经学习了不少Linux的命令了,也已经比较熟悉命令行的用法了。其最基本用法是这样的:
在终端输入命令(比如输入ls命令)。
命令的运行结果显示在终端中。
但是我们还不知道的是:其实我们可以重定向命令的运行结果。
重定向,是什么意思呢?简单来说,就是我们可以把本来要显示在终端的命令结果,输送到别的地方:
到文件中或者作为其他命令的输入(命令的链接,或者叫命令管道)。
把两个命令连起来使用,一个命令的输出作为另一个命令的输入,这就构成了管道。
管道的英语是pipeline。你可以想象一个个水管,连接起来。这一个水管流出来的水(输出),如果接上另一个水管,水是不是就流入另一个水管,成为另一个水管的输入了?
当然了,在计算机科学中,流(英语是stream)的含义是比较难理解的,也比较丰富,不同的情况下含义也不太一样。如果把它比作水流可能不完全。
知乎上就有一篇帖子,大家可以看看:
《如何理解编程语言中「流」(stream)的概念?》
http://www.zhihu.com/question/27996269
我们常可以看到这样的字样:位元流,字节流,资料流,视频流,音频流,流媒体,流算法,流处理,数据流挖掘,等等。
在维*基百科中,流的简单定义是这样的,供大家参考:
《In computer science, a stream is a sequence of data elements made available over time. A stream can be thought of as items on a conveyor belt being processed one at a time rather than in large batches.》
以上这段英语翻译过来大致意思是(有点难翻译...翻得不好不要拍我):
《在计算机科学中,流是时间上可用的一系列数据元素。我们可以把流比喻成传送带上的物件,每个时间点传输一个,而不是多个打包传输。》
(翻得连我自己都快吐了...如果要扔我鸡蛋请再多扔几个面团过来,这样我可以做鸡蛋灌饼)
前面说了,我们会学习如何把命令的输出结果重定向到其他地方:
哪里:文件或者另一个命令的输入。
如何实现:通过在命令间插入特定的符号(这些符号可以被称为《重定向流》符号)。下面我们会学到,有好几种符号。
可以用下图来做一个小结:
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
可以看到,命令的输出可以有三个去向:
终端
文件
其他命令的输入
到目前为止,我们只用过第一种形式:把命令的输出结果显示在终端。
我们岂能就此罢休呢对吧,肯定要乘胜追击啊。一不做二不休啊。
重定向流从Unix时代就已经是很重要的概念了,后来Linux出现,重定向流的原理依旧沿用。
重定向流将会改变我们看待终端命令行的方式,所以这课很重要。
借着这一课,我们将把我们的命令行的造诣提升到另一个层级。如果之前是命令行的小学,那么这一课学完就基本可以初中毕业了。
你也许看到过一些Linux高手输入命令,经常会输入一大串,然后回车。这一大串命令中很可能就用到了我们今天学的流,管道和重定向。
>和>>:重定向到文件
我们先从最简单的开始。最简单的操作就是把命令的输出结果重定向到文件中,就不会在终端显示命令运行结果了。
准备工作:再谈cut命令
在开始学习>和>>这两个符号的用法之前,我们需要创建一些文件。
在创建文件之前,我们来谈谈cut命令的进阶用法。cut是英语《剪切》的意思,用于从文件中剪切出来一部分内容。
上一课《【Linux探索之旅】第三部分第一课:数据处理,慢条斯理》中我们学习了cut命令,但没有深入讲解,只讲了比较基本的用法(-c参数:根据字符数来剪切)。
我们再来学习一下cut命令的其他参数。
cut命令进阶:根据分隔符来剪切
我们来看一种特殊的文件形式:CSV格式。
CSV是Comma Separated Values的缩写,翻成中文是《逗号分隔值》。
以下摘自百度百科:
=================
《逗号分隔值(Comma-Separated Values,CSV,有时也称为字符分隔值,因为分隔字符也可以不是逗号),其文件以纯文本形式存储表格数据(数字和文本)。纯文本意味着该文件是一个字符序列,不含必须像二进制数字那样被解读的数据。CSV文件由任意数目的记录组成,记录间以某种换行符分隔;每条记录由字段组成,字段间的分隔符是其它字符或字符串,最常见的是逗号或制表符。通常,所有记录都有完全相同的字段序列。》
=================
CSV文件的后缀名是.csv,通常可以被Excel等软件打开,打开之后会把分隔符隔开的各个数值填充到表格里。
我们来构建一个CSV文件。因为我们要用逗号作为分隔符,来学习cut命令的进阶使用:根据分隔符来剪切。
假设我们有一个人数不多的班级,作为老师我们需要统计新近一次考试的成绩。我们为此制作了一个表格,并按照顺序把数据写入表格。
我们的CSV文件的内容可以如下,我们用Nano这样的文本编辑器来编写这个CSV文件,并且取名:notes.csv (note是英语《成绩》的意思)。
Mack,95 / 100,很不错
Matthew,30 / 100,跟平时一样水
Louise,70 / 100,有进步
Luke,54 / 100,接近平均分了
John,68 / 100,不错,但还可以更好
Samuel,100 / 100,总是那么完美
David,40 / 100,退步挺大呀
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
如上图所示,我们的notes.csv文件中每一行由三部分组成,每部分由一个逗号分隔:
学生名字
成绩(满分是100分)
评语
现在假如我们要从notes.csv文件中提取名字那一列,怎么办呢?我们不能用cut命令的-c参数啊,毕竟每个名字的字符数不相等。
聪明如你应该想到了。是的,我们看到文件中每一行的每一部分是用分隔符来隔开的,所以我们可以这样做:
需要用到两个参数:
-d参数:d是delimiter的缩写,是《分隔符》的意思。用于指定用什么分隔符(比如逗号,分号,双引号等等)。
-f参数:f是field的缩写,是《区域》的意思。表示剪切下用分隔符分隔的哪一块或哪几块区域。
我们的notes.csv文件是用逗号来分隔三个部分的,我们要剪切下来的是名字那一列,也就是第一部分。因此我们可以这样使用:
cut -d , -f 1 notes.csv
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
怎么样,很不错吧。我们通过cut命令的两个参数就实现了从notes.csv文件中剪切下第一部分(名字)的想法。
那如果我们只想剪切下评语部分呢?评语是第三部分:
cut -d , -f 3 notes.csv
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
那如果我们要第一和第三部分呢?可以这样:
cut -d , -f 1,3 notes.csv
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
同样地,我们可以用 cut -d , -f 2- notes.csv 来剪切第二部分直到最后的内容:
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
好了,现在准备工作做好了,我们可以来学习重定向流符号了。
>:重定向到新的文件
我们知道虽然我们刚才用cut命令从notes.csv文件中剪切出来一些部分,但原始的notes.csv文件是不变的。
我们现在想要将剪切出来的部分储存到一个文件中,而不是像之前那样显示在终端里。
(为了方便演示,我们在家目录下新建一个redirect目录,redirect是英语《重定向》的意思。将之前的notes.csv文件放到这个目录下,再用cd redirect命令定位到这个目录)
我们需要用到>这个神奇的符号,如果你是美式键盘,那么可以在句号那个键找到这个符号,在句号的上面。所以要输入这个符号,可以用Shift加上句号那个键。做网络前端开发的程序员应该对这个符号不陌生,因为HTML语言里到处是<>这对符号。
这个符号可以将命令的输出结果重定向到你自己选择的文件中。例如:
cut -d , -f 1 notes.csv > students.txt
student是英语《学生》的意思。如果你运行上述命令,那么终端不会有任何显示。因为我们将cut命令的运行结果(剪切了名字那一列)重定向到students.txt文件中了。
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
可以看到,我们用cat命令打印了student.txt文件的内容,正是cut -d , -f 1 notes.csv 这句命令的运行结果。
我们用ls命令查看redirect目录下的文件,发现多了一个students.txt文件。
怎么样,>这个符号很有用吧。不过使用时要小心,因为>符号会把输出重定向到文件中,如果此文件不存在,则新建一个文件;如果此文件已经存在,那就会把文件内容覆盖掉(清除原有内容,然后写入文件),而且是不会征求用户确认的。
有时候,我们既不想将命令的输出显示在终端,又不想将其储存到文件中,怎么办呢?
Linux中有一个俗称《黑洞》的文件,就是 /dev/null
null是英语《无,空》的意思。
/dev/null 文件是特殊文件,不是一个目录。此文件具有唯一的属性:它总是空的。它能使发送到/dev/null 的任何数据作废,就好像这些数据掉进了无底的黑洞一般。
因此,假如我们不需要在终端显示刚才那个cut命令的结果,也不想存储到文件里,那么可以这么做:
cut -d , -f 1 notes.csv > /dev/null
>>: 重定向到文件末尾
我们已经知道,单独一个>符号可以实现重定向到新的文件(覆盖文件内容),那么两个连在一起的>符号有什么作用呢?
>>的作用与>是类似的,不过它不会像>那么危险(如果文件已经存在,>符号会覆盖文件内容),而是将重定向的内容写入到文件末尾,起到追加的作用。如果文件不存在,也会被创建。
我们就来实践一下:
cut -d , -f 1 notes.csv >> students.txt
因为我们上一个例子中已经用>符号来重定向名字那列的内容到students.txt文件中了,所以上面的命令会追加同样内容到students.txt的末尾。
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
我们用cat命令打印了students.txt文件的内容,可以看到有两遍notes.csv中名字列的内容。
>>符号在很多情况下非常有用,比如你人不在电脑前,而你又想让终端为你记录程序运行的结果,就可以在一个日志文件的末尾一直写入。例如:
command >> results.log
小结
我们方才学习了两个重定向流符号:
>:重定向到文件中。如果文件已存在,则覆盖文件内容;文件不存在,则创建文件。
>>:重定向到文件末尾。文件不存在,则创建文件。
可以用下图演示两个符号的原理:
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
2>,2>>,2>&1:重定向错误输出
怎么样,流的重定向是不是很有趣?那么我们继续学习其他的重定向流符号。
我们首先来学点新知识。
stdin,stdout,stderr:标准输入,标准输出,标准错误输出
这三个又是什么东东?这一课新东西果然多。
一般学编程,到某个阶段,总应该会碰到这三位仁兄的。所以既然逃不了,不如勇敢来面对。
对于我们的终端命令行,我们从键盘向终端输入数据,这是标准输入,也就是stdin。
终端接收键盘输入的命令,会产生两种输出:
标准输出:stdout。指终端输出的所有信息(不包括错误信息)。
标准错误输出:stderr。指终端输出的错误信息。
第一个stdout就是我们到目前为止看到的那些Linux命令的正常运行结果,比如在终端中运行ls命令,我们以前也看到了它列出当前目录下所有文件。
那什么是标准错误输出呢?其实我们以前也看到过,只是见得不多而已。
我们用一个例子来说明。
假设,我们运行cat notes.csv命令,想要显示notes.csv文件的内容。将会有两种结果:
如果一切顺利(notes.csv文件存在于当前目录,而且我们有权限这么做),那么终端就会显示其内容。这是标准输出。
如果出错(比如notes.csv文件不存在),那么终端就会显示错误信息。这是标准错误输出。
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
如上图所示,我们在redirect这个目录中运行cat notes.csv时,因为文件存在,而且我们有权限对其执行cat命令,所以打印出了文件内容。这就是标准输出。
接着,我们用cd .. 命令定位到了上一级目录,也就是用户的家目录,在这个目录中我们并没有创建notes.csv文件,所以cat notes.csv命令自然就输出了错误信息:No such file or directory,翻译过来就是《不存在此文件或目录》。这就是标准错误输出。
默认情况下,标准输出和标准错误输出都会显示在终端,这也是为什么我们之前对它们的区别并没有那么在意的原因,因为长得挺像的,都在终端输出。
我们可以用下图来演示:
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
这三个你也可以把它们看作流:
stdin:标准输入流。standard input的缩写。标准输入是指输入至程序的数据(通常是文件)。程序要求以读(read)操作来传输数据。并非所有程序都要求输入。如dir或ls程序运行时不用任何输入。 除非重定向,输入是预期由键盘获取的。 标准输入的文件描述符为 0 (零);在POSIX <unistd.h> 的定义是 STDIN_FILENO;相对应的 <stdio.h> 变数为 FILE* stdin ;类似地, <iostream> 变数为 std::cin 。
stdout:标准输出流。standard output的缩写。标准输出是指程序写输出数据的流。程序要求数据传输使用写的运算。并非所有程序都要求输出。如mv或ren程序在成功完成时是没有输出的。 除非重导向,输出是预期显示在终端上的。 标准输出的文件描述符为 1 (一)。POSIX <unistd.h> 定义是 STDOUT_FILENO;相对应的 <stdio.h> 变数为 FILE* stdout ;类似地, <iostream> 变数为 std::cout 。
stderr:标准错误输出流。standard error的缩写。标准错误输出是另一个输出流,用于输出错误消息或诊断。它独立于标准输出,且标准输出和标准错误输出可以分别被重定向。标准错误输出的文件描述符为 2 (二);POSIX <unistd.h> 定义为 STDERR_FILENO;相对的 <stdio.h> 变数 FILE* stderr。C++ <iostream> 的变数为: std::cerr。
文件描述符 名字 解释
0 stdin 标准输入
1 stdout 标准输出
2 stderr 标准错误输出
那什么是文件描述符呢?
文件描述符的英语是File Descriptor,简称fd。
文件描述符是计算机科学中的一个术语,要完全讲清楚可能要用单独的一课。我们就不深究了。
文件描述符是一个用于表述指向文件的引用的抽象化概念。这定义本身也有点抽象。我们不需要太深入了解。大致只需要知道:
《文件描述符在形式上是一个非负整数。实际上,它是一个索引值,指向操作系统内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符》。
文件描述符通常是Unix,Linux等系统的概念。在Windows中,也有类似的概念,但是Windows中称为《句柄》,就是handle。
好了,重新回到我们的话题。刚才我们已经学习了用>和>>两个符号可以将输出重定向到文件中,那么我们在出错的情况下是不是也可以用>和>>将标准错误输出也重定向到文件中呢?我们来试试:
cat not_exist_file.csv > results.txt
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
如上图所示,因为 not_exist_file.csv 这个文件不存在(正如其名),所以产生了错误信息。但是这个错误信息却并没有如我们所愿的写入到results.txt文件中,而是仍旧在终端输出了。这是为什么呢?不是说好的>符号用于重定向输出到文件的吗?
其实,>和>>符号只是将标准输出重定向到文件。并不能将标准错误输出重定向到文件。
那么我们要重定向标准错误输出,该怎么办呢?
我们就要用到 2> 这个符号,是的,就是在>这个符号左边紧挨着写一个2。
为什么是2呢?记得上面说的吗?标准错误输出的文件描述符是2,所以这里的2表示标准错误输出。如果没有2,单独的>符号就是重定向标准输出(文件描述符为1)。
我们补充一下刚才的命令:
cat not_exist_file.csv > results.txt 2> errors.log
这个命令里有两个重定向:
> results.txt:将标准输出重定向到results.txt文件中。
2> errors.log:将标准错误输出重定向到errors.log文件中。
也就是说,假如 not_exist_file.csv这个文件确实存在,将其内容写入results.txt文件中;假如文件不存在,将错误信息写入errors.log文件中。
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
如上图所示,我们运行了cat not_exist_file.csv > results.txt 2> errors.log这个命令,因为not_exist_file.csv这个文件不存在,所以results.txt文件是空的;errors.log文件的内容是错误信息。
类似地,2>>符号用于将标准错误输出重定向到文件末尾。
合并输出
上面我们学习了如何将标准输出和标准错误输出分别重定向到不同文件。但是有的时候,我们比较任性,我们就想把标准输出和标准错误输出都重定向到同一个地方。怎么做呢?
须要使用 2>&1 这个组合符号。
看着怪怪的对吧?由四个字符组成。这个符号的作用是:将标准错误输出重定向到与标准输出相同的地方。
我们用实例演示一下:
cat not_exist_file.csv > results.txt 2>&1
上面的命令的作用是:将cat not_exist_file.csv这个命令的所有输出(标准输出和标准错误输出)都重定向到results.txt文件中。
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
如上图所示,运行cat not_exist_file.csv > results.txt 2>&1命令之后,因为not_exist_file.csv这个文件不存在,但又因为加了2>&1这个符号,所以标准输出(为空)和标准错误输出(cat: not_exist_file.csv: No such file or directory)都重定向到results.txt文件中了。
然后大家是否觉得要将标准输出和标准错误输出都重定向到文件末尾,应该是这样写:2>>&1 呢?
其实不然,这样是不对的。我们还是保持2>&1这个组合不变,只改变前面的符号就行了。例如:
cat not_exist_file.csv >> results.txt 2>&1
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
可以看到,又追加了一条错误信息到results.txt文件中。
小结
2>:将标准错误输出重定向到文件。如果文件已经存在,则覆盖文件内容;如果不存在,则创建文件。
2>>:将标准错误输出重定向到文件末尾。如果文件不存在,则创建文件。
2>&1:将标准输出和标准错误输出都重定向到一个地方。
用下图来演示:
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
上图中,我故意没有加>>和2>>,不然这图就太复杂了。其实>和>>,2>和2>>的区别就是前者覆盖文件内容,后者追加内容到文件。
<,<<:从文件或键盘读取
到目前为止,这一课我们只讲了如何重定向命令的输出,也就是决定命令输出的信息的去向。那么接着我们可以做一点相反的事情:决定命令的输入来自哪里。
当然了,上面也说了,不是所有的命令都有输入,也不是所有的命令都有输出。
到目前为止,我们的命令的输入都来自于后面接的参数,这些参数有些是文件名,有些是目录名,等等。
但我们其实可以使命令的输入来自于文件或者键盘输入。如下图所示:
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
<:从文件中读取
看到这个<符号,是不是想到了之前的>符号呢?
是的,这对孪生兄弟,原理类似但是功能正相反。<符号用于指定命令的输入。
我们用一个简单的例子来演示:
cat < notes.csv
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
如上图所示,cat < notes.csv的运行结果和cat notes.csv (不用重定向流符号)一模一样,都是在终端打印notes.csv的内容,那我们为什么需要<符号呢?
事实上,虽然cat < notes.csv的运行结果和cat notes.csv一样,但是原理却不一样:
cat notes.csv :这种情况下,cat命令接受的输入是notes.csv这个文件名,那么它要先打开notes.csv文件,然后打印出文件内容。
cat < notes.csv :这种情况下,cat命令接受的输入直接是notes.csv这个文件的内容,cat命令只负责将其内容打印。而打开文件,将文件内容传递给cat命令的工作则交给shell程序(也就是控制终端的程序)来完成。
所以,虽然结果看似一样,但是中间的过程确实不一样的。
<<:从键盘读取
<<符号的作用是将键盘的输入重定向为某个命令的输入,很多情况下都很有用。
我们用实例来说明:
sort -n << END
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
如上图所示,输入这条命令之后,回车,终端就进入了键盘输入模式,看到那个>符号和其后闪动的光标了么?
就是让你输入数据的。
我们知道sort -n的作用是按照从小到大进行排列。那么我们就输入一些数值吧(每输一个数值,用回车键来换行,接着输入下一个数值,输入END来结束输入,END被称为结束字符串。当然了,你可以用其他字符串,比如haha,nihao,不一定要用END):
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
可以看到,sort -n命令将我们输入的一串数值进行了由小到大的排序。
我们再试试其他命令与<<符号的配合,这次我们用wc命令吧,wc命令用于统计字符等,如果配合-m参数就是统计字符数。
wc -m << END
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
可以看到,《How many characters are there in this sentence ?》这句话中有49个字符。
这句话翻成中文就是《这句话中有多少个字符?》
小结
<:将命令的输入重定向为文件内容。
<<:将命令的输入重定向为键盘输入,以逐行输入的模式(回车键换行)。所有输入的行都将在输入结束字符串(例如上面例子中的END)之后发送给命令。
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
当然了,我们也可以将之前学习的输出重定向符号和这一节的输入重定向符号结合使用:
sort -n << END > numbers_sorted.txt 2>&1
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
如上图所见,以上命令将sort -n命令对数值排序的结果都输入到numbers_sorted.txt文件中,如果有错误信息也输入。
|:管道
好了,终于来到本课的最后一节了。
是不是有点累呢?如果是的话,可以去烤一只烤鸭。为什么小编不像以前一样说烤鸡了呢?是因为最近有一对好友夫妇在法国Aix en Provence开了一家烤鸭店,他们的公众号发了几张诱人的烤鸭照片,看得小编直流哈喇子。但是吃不到啊,小编住在Nice附近,离Aix en Provence有近3个小时火车的路程。唉,以后去吧~
好了,不扯烤鸭了,言归正传。
这一节要学的符号,将会成为你以后Linux生涯中最常用的符号之一,使用率绝对高过这一课学的其他符号。
这个符号就是所谓的《管道符号》:|
是的,就是美式键盘上位于反斜杠那个键的那个符号,要输入这个符号,需要使用Shift + \
|符号既然被称为《管道符》,那么其作用就是《建立命令管道》咯。
是的,还记得本课开篇的时候我们提到的那个比喻吗?一个命令的输出可以作为另一个命令的输入,就好像将两根水管接起来一样,前一根水管流出来的水就会流入后一根水管了。
管道也算是重定向流的一种。
原理
将两个命令连成管道,这是什么意思呢?简单的说就是将一个命令的输出作为另一个命令的输入,如下图所示:
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
大致来说:命令1的输出立即会变成命令2的输入。使用这个原理,我们可以用|符号连接无穷多个命令,构成很长的命令管道。
管道符绝对使Linux命令的威力增加N倍。之前我们也说了,Linux中的命令(很多都是从Unix时代承袭下来的),每一个的功能虽然有限,但是却在它们自己的岗位上尽忠职守,工作做得棒棒哒。所以单独一条Linux命令可能功能有限,但是一旦《铁索连环》,那可是会结合各个命令的功能,其强大不难想见。
实践
我们用几个实例来学习管道吧。
按学生名字排序
你应该还记得我们的notes.csv文件,其中有三部分,用逗号隔开的,第一部分是学生名字,第二部分是成绩,第三部分是评语。
之前我们用cut -d , -f 1 notes.csv 命令来剪切了名字那一列。如果你还记得我们前一课学的sort命令,它是用于排序文件内容。
那么为什么不把这两个命令用管道符连接起来呢?我们可以用sort命令对cut命令提取到的名字列进行排序:
cut -d , -f 1 notes.csv | sort
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
如上图所见,我们用sort命令对名字列按照首字母的字典顺序进行了排序。
怎么样,管道是不是很有意思?
如果我们将上面的命令再扩充一下,配合之前学习的输出重定向符号,就变成了这样:
cut -d , -f 1 notes.csv | sort > sorted_names.txt
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
可以看到,我们将sort命令排序的结果重定向到sorted_names.txt文件中了。
根据大小排序目录
之前我们学过,du命令可以深入遍历当前目录下每个子目录,把所有文件的大小都做一个统计。
我们可以用cd命令来回到我们的家目录。然后运行du命令。
问题是:du命令要运行挺久的,因为小编家目录下文件很多。
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
单独用du命令的缺点我们也有目共睹了,一是可能要运行很久(如果文件很多),二是显示结果没有排序,杂乱无章。
但如果我们这样做就会清爽很多:
du | sort -nr | head
还记得head命令的用法么?如果不用-n参数指定显示行数,那么head会默认显示前10行。
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
所以以上命令的作用是:
du 深入遍历当前目录下每个子目录,把所有文件的大小都做一个统计
sort -nr sort命令的-n参数是按以数值来排序(此处是文件大小)排序,默认是小的在前;-r参数是倒序排列,有了-r参数,-n参数就变成大的数值在前了
head 列出前十个最大的数值(这里是文件大小)
列出包含关键字的文件
还记得我们的好朋友grep命令吗?之前的课中有学过,这个命令很强大,可以在文件中查找关键字,并且显示关键字所在的行。但有时,我们会觉得grep显示的信息太冗长了。每一行不仅有文件名,还有关键字出现的那一行文本,等等。
我们可以运行以下命令试试:
sudo grep log -Ir /var/log | cut -d : -f 1 | sort | uniq
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
这个命令做了什么呢?让我们一步步来分解:
sudo grep log -Ir /var/log :遍历/var/log这个目录及其子目录,列出所有包含log这个关键字的行。-I参数用于排除二进制文件。-r参数用于递归遍历。sudo命令是为了以root身份查找系统文件夹/var/log。
cut -d : -f 1 从命令1的输出结果中只剪切出文件名那一列(由冒号分隔的第一个区域)。
sort 将文件名的列以首字母的字典顺序进行排序。
uniq : 去掉重复的文件名。
小结
小结很简单,因为管道符的基本作用比较简单,就是将一个命令的输出重定向为另一个命令的输入。如下图所示:
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
记住这个基本原理就好了。
好了,终于这一课结束了。是不是有点晕,如果觉得还没怎么掌握,那需要再读一遍本课程,参考一些课外读物,自己在终端上多练习。尽情发挥你的想象力,来创造出各种命令的组合吧。
总结
Linux命令的结果(标准输出),我们不一定要显示在终端里,也可以将其存放在一个文件里,只需要在命令后加上 > 符号,然后接文件名就可以了。例如 ls > file_list.txt 就会把ls命令的结果(当前目录所有文件的列表)存放到file_list.txt文件中,不在终端显示了。
>> 符号可以追加内容。>符号会把文件内容清空,再写入。如果文件已经存在,那么>>符号会在文件末尾追加写入内容。
2>和2>>符号用于重定向标准错误输出到文件中。2>&1符号用于将标准错误输出和标准输出重定向到相同地方。
<符号重定向命令的输入为文件内容,<<符号重定向命令的输入为键盘输入。
管道符号|可以将命令连接起来,好像一个个对接的管道一样,前一个命令的输出成为后一个命令的输入。
第三部分第三课预告
今天的课就到这里,一起加油吧!
下一课我们学习:监视系统活动,滴水不漏
新朋友请关注「程序员联盟」微信搜公众号 ProgrammerLeague
程序员联盟官网:
coderunity点com
程序员联盟论坛:
coderunity点com/bbs/
小编微信号: frogoscar
小编邮箱: enmingx@gmail.com
【Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下】
http://toutiao.com/a6193788933316428033/?iid=3041659310&app=news_article&tt_from=android_share&utm_medium=toutiao_android&utm_campaign=client_share
如:
[root@iZ25dcp92ckZ multepoolserver]# cat aaa.txt
cat: aaa.txt: 没有那个文件或目录
[root@iZ25dcp92ckZ multepoolserver]# cat aaa.txt > notexist.txt 2>&1
[root@iZ25dcp92ckZ multepoolserver]# cat notexist.txt
cat: aaa.txt: 没有那个文件或目录
————————————————————————————————————
./multepoolser > echoOut.txt
./tianxia > appleOut.txt 2>&1
————————————————————————————————————————————————————————
内容简介
1、第三部分第二课:流、管道、重定向,三管齐下
2、第三部分第三课预告:监视系统活动,滴水不漏
流、管道、重定向,三管齐下
这一课我们来学一些非常有用的内容,而且相当有意思,而且内容很多,而且有可能颠覆你的三《观》(毕竟三管齐下,不颠覆三观也难)。
今天的标题中的三个名称,听上去就怪怪的。什么流,管道,重定向,都啥玩意啊。不过希望学完这课,大家能够有拨云见雾的感觉。
到目前为止,我们已经学习了不少Linux的命令了,也已经比较熟悉命令行的用法了。其最基本用法是这样的:
在终端输入命令(比如输入ls命令)。
命令的运行结果显示在终端中。
但是我们还不知道的是:其实我们可以重定向命令的运行结果。
重定向,是什么意思呢?简单来说,就是我们可以把本来要显示在终端的命令结果,输送到别的地方:
到文件中或者作为其他命令的输入(命令的链接,或者叫命令管道)。
把两个命令连起来使用,一个命令的输出作为另一个命令的输入,这就构成了管道。
管道的英语是pipeline。你可以想象一个个水管,连接起来。这一个水管流出来的水(输出),如果接上另一个水管,水是不是就流入另一个水管,成为另一个水管的输入了?
当然了,在计算机科学中,流(英语是stream)的含义是比较难理解的,也比较丰富,不同的情况下含义也不太一样。如果把它比作水流可能不完全。
知乎上就有一篇帖子,大家可以看看:
《如何理解编程语言中「流」(stream)的概念?》
http://www.zhihu.com/question/27996269
我们常可以看到这样的字样:位元流,字节流,资料流,视频流,音频流,流媒体,流算法,流处理,数据流挖掘,等等。
在维*基百科中,流的简单定义是这样的,供大家参考:
《In computer science, a stream is a sequence of data elements made available over time. A stream can be thought of as items on a conveyor belt being processed one at a time rather than in large batches.》
以上这段英语翻译过来大致意思是(有点难翻译...翻得不好不要拍我):
《在计算机科学中,流是时间上可用的一系列数据元素。我们可以把流比喻成传送带上的物件,每个时间点传输一个,而不是多个打包传输。》
(翻得连我自己都快吐了...如果要扔我鸡蛋请再多扔几个面团过来,这样我可以做鸡蛋灌饼)
前面说了,我们会学习如何把命令的输出结果重定向到其他地方:
哪里:文件或者另一个命令的输入。
如何实现:通过在命令间插入特定的符号(这些符号可以被称为《重定向流》符号)。下面我们会学到,有好几种符号。
可以用下图来做一个小结:
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
可以看到,命令的输出可以有三个去向:
终端
文件
其他命令的输入
到目前为止,我们只用过第一种形式:把命令的输出结果显示在终端。
我们岂能就此罢休呢对吧,肯定要乘胜追击啊。一不做二不休啊。
重定向流从Unix时代就已经是很重要的概念了,后来Linux出现,重定向流的原理依旧沿用。
重定向流将会改变我们看待终端命令行的方式,所以这课很重要。
借着这一课,我们将把我们的命令行的造诣提升到另一个层级。如果之前是命令行的小学,那么这一课学完就基本可以初中毕业了。
你也许看到过一些Linux高手输入命令,经常会输入一大串,然后回车。这一大串命令中很可能就用到了我们今天学的流,管道和重定向。
>和>>:重定向到文件
我们先从最简单的开始。最简单的操作就是把命令的输出结果重定向到文件中,就不会在终端显示命令运行结果了。
准备工作:再谈cut命令
在开始学习>和>>这两个符号的用法之前,我们需要创建一些文件。
在创建文件之前,我们来谈谈cut命令的进阶用法。cut是英语《剪切》的意思,用于从文件中剪切出来一部分内容。
上一课《【Linux探索之旅】第三部分第一课:数据处理,慢条斯理》中我们学习了cut命令,但没有深入讲解,只讲了比较基本的用法(-c参数:根据字符数来剪切)。
我们再来学习一下cut命令的其他参数。
cut命令进阶:根据分隔符来剪切
我们来看一种特殊的文件形式:CSV格式。
CSV是Comma Separated Values的缩写,翻成中文是《逗号分隔值》。
以下摘自百度百科:
=================
《逗号分隔值(Comma-Separated Values,CSV,有时也称为字符分隔值,因为分隔字符也可以不是逗号),其文件以纯文本形式存储表格数据(数字和文本)。纯文本意味着该文件是一个字符序列,不含必须像二进制数字那样被解读的数据。CSV文件由任意数目的记录组成,记录间以某种换行符分隔;每条记录由字段组成,字段间的分隔符是其它字符或字符串,最常见的是逗号或制表符。通常,所有记录都有完全相同的字段序列。》
=================
CSV文件的后缀名是.csv,通常可以被Excel等软件打开,打开之后会把分隔符隔开的各个数值填充到表格里。
我们来构建一个CSV文件。因为我们要用逗号作为分隔符,来学习cut命令的进阶使用:根据分隔符来剪切。
假设我们有一个人数不多的班级,作为老师我们需要统计新近一次考试的成绩。我们为此制作了一个表格,并按照顺序把数据写入表格。
我们的CSV文件的内容可以如下,我们用Nano这样的文本编辑器来编写这个CSV文件,并且取名:notes.csv (note是英语《成绩》的意思)。
Mack,95 / 100,很不错
Matthew,30 / 100,跟平时一样水
Louise,70 / 100,有进步
Luke,54 / 100,接近平均分了
John,68 / 100,不错,但还可以更好
Samuel,100 / 100,总是那么完美
David,40 / 100,退步挺大呀
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
如上图所示,我们的notes.csv文件中每一行由三部分组成,每部分由一个逗号分隔:
学生名字
成绩(满分是100分)
评语
现在假如我们要从notes.csv文件中提取名字那一列,怎么办呢?我们不能用cut命令的-c参数啊,毕竟每个名字的字符数不相等。
聪明如你应该想到了。是的,我们看到文件中每一行的每一部分是用分隔符来隔开的,所以我们可以这样做:
需要用到两个参数:
-d参数:d是delimiter的缩写,是《分隔符》的意思。用于指定用什么分隔符(比如逗号,分号,双引号等等)。
-f参数:f是field的缩写,是《区域》的意思。表示剪切下用分隔符分隔的哪一块或哪几块区域。
我们的notes.csv文件是用逗号来分隔三个部分的,我们要剪切下来的是名字那一列,也就是第一部分。因此我们可以这样使用:
cut -d , -f 1 notes.csv
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
怎么样,很不错吧。我们通过cut命令的两个参数就实现了从notes.csv文件中剪切下第一部分(名字)的想法。
那如果我们只想剪切下评语部分呢?评语是第三部分:
cut -d , -f 3 notes.csv
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
那如果我们要第一和第三部分呢?可以这样:
cut -d , -f 1,3 notes.csv
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
同样地,我们可以用 cut -d , -f 2- notes.csv 来剪切第二部分直到最后的内容:
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
好了,现在准备工作做好了,我们可以来学习重定向流符号了。
>:重定向到新的文件
我们知道虽然我们刚才用cut命令从notes.csv文件中剪切出来一些部分,但原始的notes.csv文件是不变的。
我们现在想要将剪切出来的部分储存到一个文件中,而不是像之前那样显示在终端里。
(为了方便演示,我们在家目录下新建一个redirect目录,redirect是英语《重定向》的意思。将之前的notes.csv文件放到这个目录下,再用cd redirect命令定位到这个目录)
我们需要用到>这个神奇的符号,如果你是美式键盘,那么可以在句号那个键找到这个符号,在句号的上面。所以要输入这个符号,可以用Shift加上句号那个键。做网络前端开发的程序员应该对这个符号不陌生,因为HTML语言里到处是<>这对符号。
这个符号可以将命令的输出结果重定向到你自己选择的文件中。例如:
cut -d , -f 1 notes.csv > students.txt
student是英语《学生》的意思。如果你运行上述命令,那么终端不会有任何显示。因为我们将cut命令的运行结果(剪切了名字那一列)重定向到students.txt文件中了。
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
可以看到,我们用cat命令打印了student.txt文件的内容,正是cut -d , -f 1 notes.csv 这句命令的运行结果。
我们用ls命令查看redirect目录下的文件,发现多了一个students.txt文件。
怎么样,>这个符号很有用吧。不过使用时要小心,因为>符号会把输出重定向到文件中,如果此文件不存在,则新建一个文件;如果此文件已经存在,那就会把文件内容覆盖掉(清除原有内容,然后写入文件),而且是不会征求用户确认的。
有时候,我们既不想将命令的输出显示在终端,又不想将其储存到文件中,怎么办呢?
Linux中有一个俗称《黑洞》的文件,就是 /dev/null
null是英语《无,空》的意思。
/dev/null 文件是特殊文件,不是一个目录。此文件具有唯一的属性:它总是空的。它能使发送到/dev/null 的任何数据作废,就好像这些数据掉进了无底的黑洞一般。
因此,假如我们不需要在终端显示刚才那个cut命令的结果,也不想存储到文件里,那么可以这么做:
cut -d , -f 1 notes.csv > /dev/null
>>: 重定向到文件末尾
我们已经知道,单独一个>符号可以实现重定向到新的文件(覆盖文件内容),那么两个连在一起的>符号有什么作用呢?
>>的作用与>是类似的,不过它不会像>那么危险(如果文件已经存在,>符号会覆盖文件内容),而是将重定向的内容写入到文件末尾,起到追加的作用。如果文件不存在,也会被创建。
我们就来实践一下:
cut -d , -f 1 notes.csv >> students.txt
因为我们上一个例子中已经用>符号来重定向名字那列的内容到students.txt文件中了,所以上面的命令会追加同样内容到students.txt的末尾。
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
我们用cat命令打印了students.txt文件的内容,可以看到有两遍notes.csv中名字列的内容。
>>符号在很多情况下非常有用,比如你人不在电脑前,而你又想让终端为你记录程序运行的结果,就可以在一个日志文件的末尾一直写入。例如:
command >> results.log
小结
我们方才学习了两个重定向流符号:
>:重定向到文件中。如果文件已存在,则覆盖文件内容;文件不存在,则创建文件。
>>:重定向到文件末尾。文件不存在,则创建文件。
可以用下图演示两个符号的原理:
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
2>,2>>,2>&1:重定向错误输出
怎么样,流的重定向是不是很有趣?那么我们继续学习其他的重定向流符号。
我们首先来学点新知识。
stdin,stdout,stderr:标准输入,标准输出,标准错误输出
这三个又是什么东东?这一课新东西果然多。
一般学编程,到某个阶段,总应该会碰到这三位仁兄的。所以既然逃不了,不如勇敢来面对。
对于我们的终端命令行,我们从键盘向终端输入数据,这是标准输入,也就是stdin。
终端接收键盘输入的命令,会产生两种输出:
标准输出:stdout。指终端输出的所有信息(不包括错误信息)。
标准错误输出:stderr。指终端输出的错误信息。
第一个stdout就是我们到目前为止看到的那些Linux命令的正常运行结果,比如在终端中运行ls命令,我们以前也看到了它列出当前目录下所有文件。
那什么是标准错误输出呢?其实我们以前也看到过,只是见得不多而已。
我们用一个例子来说明。
假设,我们运行cat notes.csv命令,想要显示notes.csv文件的内容。将会有两种结果:
如果一切顺利(notes.csv文件存在于当前目录,而且我们有权限这么做),那么终端就会显示其内容。这是标准输出。
如果出错(比如notes.csv文件不存在),那么终端就会显示错误信息。这是标准错误输出。
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
如上图所示,我们在redirect这个目录中运行cat notes.csv时,因为文件存在,而且我们有权限对其执行cat命令,所以打印出了文件内容。这就是标准输出。
接着,我们用cd .. 命令定位到了上一级目录,也就是用户的家目录,在这个目录中我们并没有创建notes.csv文件,所以cat notes.csv命令自然就输出了错误信息:No such file or directory,翻译过来就是《不存在此文件或目录》。这就是标准错误输出。
默认情况下,标准输出和标准错误输出都会显示在终端,这也是为什么我们之前对它们的区别并没有那么在意的原因,因为长得挺像的,都在终端输出。
我们可以用下图来演示:
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
这三个你也可以把它们看作流:
stdin:标准输入流。standard input的缩写。标准输入是指输入至程序的数据(通常是文件)。程序要求以读(read)操作来传输数据。并非所有程序都要求输入。如dir或ls程序运行时不用任何输入。 除非重定向,输入是预期由键盘获取的。 标准输入的文件描述符为 0 (零);在POSIX <unistd.h> 的定义是 STDIN_FILENO;相对应的 <stdio.h> 变数为 FILE* stdin ;类似地, <iostream> 变数为 std::cin 。
stdout:标准输出流。standard output的缩写。标准输出是指程序写输出数据的流。程序要求数据传输使用写的运算。并非所有程序都要求输出。如mv或ren程序在成功完成时是没有输出的。 除非重导向,输出是预期显示在终端上的。 标准输出的文件描述符为 1 (一)。POSIX <unistd.h> 定义是 STDOUT_FILENO;相对应的 <stdio.h> 变数为 FILE* stdout ;类似地, <iostream> 变数为 std::cout 。
stderr:标准错误输出流。standard error的缩写。标准错误输出是另一个输出流,用于输出错误消息或诊断。它独立于标准输出,且标准输出和标准错误输出可以分别被重定向。标准错误输出的文件描述符为 2 (二);POSIX <unistd.h> 定义为 STDERR_FILENO;相对的 <stdio.h> 变数 FILE* stderr。C++ <iostream> 的变数为: std::cerr。
文件描述符 名字 解释
0 stdin 标准输入
1 stdout 标准输出
2 stderr 标准错误输出
那什么是文件描述符呢?
文件描述符的英语是File Descriptor,简称fd。
文件描述符是计算机科学中的一个术语,要完全讲清楚可能要用单独的一课。我们就不深究了。
文件描述符是一个用于表述指向文件的引用的抽象化概念。这定义本身也有点抽象。我们不需要太深入了解。大致只需要知道:
《文件描述符在形式上是一个非负整数。实际上,它是一个索引值,指向操作系统内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符》。
文件描述符通常是Unix,Linux等系统的概念。在Windows中,也有类似的概念,但是Windows中称为《句柄》,就是handle。
好了,重新回到我们的话题。刚才我们已经学习了用>和>>两个符号可以将输出重定向到文件中,那么我们在出错的情况下是不是也可以用>和>>将标准错误输出也重定向到文件中呢?我们来试试:
cat not_exist_file.csv > results.txt
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
如上图所示,因为 not_exist_file.csv 这个文件不存在(正如其名),所以产生了错误信息。但是这个错误信息却并没有如我们所愿的写入到results.txt文件中,而是仍旧在终端输出了。这是为什么呢?不是说好的>符号用于重定向输出到文件的吗?
其实,>和>>符号只是将标准输出重定向到文件。并不能将标准错误输出重定向到文件。
那么我们要重定向标准错误输出,该怎么办呢?
我们就要用到 2> 这个符号,是的,就是在>这个符号左边紧挨着写一个2。
为什么是2呢?记得上面说的吗?标准错误输出的文件描述符是2,所以这里的2表示标准错误输出。如果没有2,单独的>符号就是重定向标准输出(文件描述符为1)。
我们补充一下刚才的命令:
cat not_exist_file.csv > results.txt 2> errors.log
这个命令里有两个重定向:
> results.txt:将标准输出重定向到results.txt文件中。
2> errors.log:将标准错误输出重定向到errors.log文件中。
也就是说,假如 not_exist_file.csv这个文件确实存在,将其内容写入results.txt文件中;假如文件不存在,将错误信息写入errors.log文件中。
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
如上图所示,我们运行了cat not_exist_file.csv > results.txt 2> errors.log这个命令,因为not_exist_file.csv这个文件不存在,所以results.txt文件是空的;errors.log文件的内容是错误信息。
类似地,2>>符号用于将标准错误输出重定向到文件末尾。
合并输出
上面我们学习了如何将标准输出和标准错误输出分别重定向到不同文件。但是有的时候,我们比较任性,我们就想把标准输出和标准错误输出都重定向到同一个地方。怎么做呢?
须要使用 2>&1 这个组合符号。
看着怪怪的对吧?由四个字符组成。这个符号的作用是:将标准错误输出重定向到与标准输出相同的地方。
我们用实例演示一下:
cat not_exist_file.csv > results.txt 2>&1
上面的命令的作用是:将cat not_exist_file.csv这个命令的所有输出(标准输出和标准错误输出)都重定向到results.txt文件中。
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
如上图所示,运行cat not_exist_file.csv > results.txt 2>&1命令之后,因为not_exist_file.csv这个文件不存在,但又因为加了2>&1这个符号,所以标准输出(为空)和标准错误输出(cat: not_exist_file.csv: No such file or directory)都重定向到results.txt文件中了。
然后大家是否觉得要将标准输出和标准错误输出都重定向到文件末尾,应该是这样写:2>>&1 呢?
其实不然,这样是不对的。我们还是保持2>&1这个组合不变,只改变前面的符号就行了。例如:
cat not_exist_file.csv >> results.txt 2>&1
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
可以看到,又追加了一条错误信息到results.txt文件中。
小结
2>:将标准错误输出重定向到文件。如果文件已经存在,则覆盖文件内容;如果不存在,则创建文件。
2>>:将标准错误输出重定向到文件末尾。如果文件不存在,则创建文件。
2>&1:将标准输出和标准错误输出都重定向到一个地方。
用下图来演示:
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
上图中,我故意没有加>>和2>>,不然这图就太复杂了。其实>和>>,2>和2>>的区别就是前者覆盖文件内容,后者追加内容到文件。
<,<<:从文件或键盘读取
到目前为止,这一课我们只讲了如何重定向命令的输出,也就是决定命令输出的信息的去向。那么接着我们可以做一点相反的事情:决定命令的输入来自哪里。
当然了,上面也说了,不是所有的命令都有输入,也不是所有的命令都有输出。
到目前为止,我们的命令的输入都来自于后面接的参数,这些参数有些是文件名,有些是目录名,等等。
但我们其实可以使命令的输入来自于文件或者键盘输入。如下图所示:
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
<:从文件中读取
看到这个<符号,是不是想到了之前的>符号呢?
是的,这对孪生兄弟,原理类似但是功能正相反。<符号用于指定命令的输入。
我们用一个简单的例子来演示:
cat < notes.csv
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
如上图所示,cat < notes.csv的运行结果和cat notes.csv (不用重定向流符号)一模一样,都是在终端打印notes.csv的内容,那我们为什么需要<符号呢?
事实上,虽然cat < notes.csv的运行结果和cat notes.csv一样,但是原理却不一样:
cat notes.csv :这种情况下,cat命令接受的输入是notes.csv这个文件名,那么它要先打开notes.csv文件,然后打印出文件内容。
cat < notes.csv :这种情况下,cat命令接受的输入直接是notes.csv这个文件的内容,cat命令只负责将其内容打印。而打开文件,将文件内容传递给cat命令的工作则交给shell程序(也就是控制终端的程序)来完成。
所以,虽然结果看似一样,但是中间的过程确实不一样的。
<<:从键盘读取
<<符号的作用是将键盘的输入重定向为某个命令的输入,很多情况下都很有用。
我们用实例来说明:
sort -n << END
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
如上图所示,输入这条命令之后,回车,终端就进入了键盘输入模式,看到那个>符号和其后闪动的光标了么?
就是让你输入数据的。
我们知道sort -n的作用是按照从小到大进行排列。那么我们就输入一些数值吧(每输一个数值,用回车键来换行,接着输入下一个数值,输入END来结束输入,END被称为结束字符串。当然了,你可以用其他字符串,比如haha,nihao,不一定要用END):
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
可以看到,sort -n命令将我们输入的一串数值进行了由小到大的排序。
我们再试试其他命令与<<符号的配合,这次我们用wc命令吧,wc命令用于统计字符等,如果配合-m参数就是统计字符数。
wc -m << END
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
可以看到,《How many characters are there in this sentence ?》这句话中有49个字符。
这句话翻成中文就是《这句话中有多少个字符?》
小结
<:将命令的输入重定向为文件内容。
<<:将命令的输入重定向为键盘输入,以逐行输入的模式(回车键换行)。所有输入的行都将在输入结束字符串(例如上面例子中的END)之后发送给命令。
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
当然了,我们也可以将之前学习的输出重定向符号和这一节的输入重定向符号结合使用:
sort -n << END > numbers_sorted.txt 2>&1
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
如上图所见,以上命令将sort -n命令对数值排序的结果都输入到numbers_sorted.txt文件中,如果有错误信息也输入。
|:管道
好了,终于来到本课的最后一节了。
是不是有点累呢?如果是的话,可以去烤一只烤鸭。为什么小编不像以前一样说烤鸡了呢?是因为最近有一对好友夫妇在法国Aix en Provence开了一家烤鸭店,他们的公众号发了几张诱人的烤鸭照片,看得小编直流哈喇子。但是吃不到啊,小编住在Nice附近,离Aix en Provence有近3个小时火车的路程。唉,以后去吧~
好了,不扯烤鸭了,言归正传。
这一节要学的符号,将会成为你以后Linux生涯中最常用的符号之一,使用率绝对高过这一课学的其他符号。
这个符号就是所谓的《管道符号》:|
是的,就是美式键盘上位于反斜杠那个键的那个符号,要输入这个符号,需要使用Shift + \
|符号既然被称为《管道符》,那么其作用就是《建立命令管道》咯。
是的,还记得本课开篇的时候我们提到的那个比喻吗?一个命令的输出可以作为另一个命令的输入,就好像将两根水管接起来一样,前一根水管流出来的水就会流入后一根水管了。
管道也算是重定向流的一种。
原理
将两个命令连成管道,这是什么意思呢?简单的说就是将一个命令的输出作为另一个命令的输入,如下图所示:
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
大致来说:命令1的输出立即会变成命令2的输入。使用这个原理,我们可以用|符号连接无穷多个命令,构成很长的命令管道。
管道符绝对使Linux命令的威力增加N倍。之前我们也说了,Linux中的命令(很多都是从Unix时代承袭下来的),每一个的功能虽然有限,但是却在它们自己的岗位上尽忠职守,工作做得棒棒哒。所以单独一条Linux命令可能功能有限,但是一旦《铁索连环》,那可是会结合各个命令的功能,其强大不难想见。
实践
我们用几个实例来学习管道吧。
按学生名字排序
你应该还记得我们的notes.csv文件,其中有三部分,用逗号隔开的,第一部分是学生名字,第二部分是成绩,第三部分是评语。
之前我们用cut -d , -f 1 notes.csv 命令来剪切了名字那一列。如果你还记得我们前一课学的sort命令,它是用于排序文件内容。
那么为什么不把这两个命令用管道符连接起来呢?我们可以用sort命令对cut命令提取到的名字列进行排序:
cut -d , -f 1 notes.csv | sort
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
如上图所见,我们用sort命令对名字列按照首字母的字典顺序进行了排序。
怎么样,管道是不是很有意思?
如果我们将上面的命令再扩充一下,配合之前学习的输出重定向符号,就变成了这样:
cut -d , -f 1 notes.csv | sort > sorted_names.txt
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
可以看到,我们将sort命令排序的结果重定向到sorted_names.txt文件中了。
根据大小排序目录
之前我们学过,du命令可以深入遍历当前目录下每个子目录,把所有文件的大小都做一个统计。
我们可以用cd命令来回到我们的家目录。然后运行du命令。
问题是:du命令要运行挺久的,因为小编家目录下文件很多。
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
单独用du命令的缺点我们也有目共睹了,一是可能要运行很久(如果文件很多),二是显示结果没有排序,杂乱无章。
但如果我们这样做就会清爽很多:
du | sort -nr | head
还记得head命令的用法么?如果不用-n参数指定显示行数,那么head会默认显示前10行。
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
所以以上命令的作用是:
du 深入遍历当前目录下每个子目录,把所有文件的大小都做一个统计
sort -nr sort命令的-n参数是按以数值来排序(此处是文件大小)排序,默认是小的在前;-r参数是倒序排列,有了-r参数,-n参数就变成大的数值在前了
head 列出前十个最大的数值(这里是文件大小)
列出包含关键字的文件
还记得我们的好朋友grep命令吗?之前的课中有学过,这个命令很强大,可以在文件中查找关键字,并且显示关键字所在的行。但有时,我们会觉得grep显示的信息太冗长了。每一行不仅有文件名,还有关键字出现的那一行文本,等等。
我们可以运行以下命令试试:
sudo grep log -Ir /var/log | cut -d : -f 1 | sort | uniq
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
这个命令做了什么呢?让我们一步步来分解:
sudo grep log -Ir /var/log :遍历/var/log这个目录及其子目录,列出所有包含log这个关键字的行。-I参数用于排除二进制文件。-r参数用于递归遍历。sudo命令是为了以root身份查找系统文件夹/var/log。
cut -d : -f 1 从命令1的输出结果中只剪切出文件名那一列(由冒号分隔的第一个区域)。
sort 将文件名的列以首字母的字典顺序进行排序。
uniq : 去掉重复的文件名。
小结
小结很简单,因为管道符的基本作用比较简单,就是将一个命令的输出重定向为另一个命令的输入。如下图所示:
Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下
记住这个基本原理就好了。
好了,终于这一课结束了。是不是有点晕,如果觉得还没怎么掌握,那需要再读一遍本课程,参考一些课外读物,自己在终端上多练习。尽情发挥你的想象力,来创造出各种命令的组合吧。
总结
Linux命令的结果(标准输出),我们不一定要显示在终端里,也可以将其存放在一个文件里,只需要在命令后加上 > 符号,然后接文件名就可以了。例如 ls > file_list.txt 就会把ls命令的结果(当前目录所有文件的列表)存放到file_list.txt文件中,不在终端显示了。
>> 符号可以追加内容。>符号会把文件内容清空,再写入。如果文件已经存在,那么>>符号会在文件末尾追加写入内容。
2>和2>>符号用于重定向标准错误输出到文件中。2>&1符号用于将标准错误输出和标准输出重定向到相同地方。
<符号重定向命令的输入为文件内容,<<符号重定向命令的输入为键盘输入。
管道符号|可以将命令连接起来,好像一个个对接的管道一样,前一个命令的输出成为后一个命令的输入。
第三部分第三课预告
今天的课就到这里,一起加油吧!
下一课我们学习:监视系统活动,滴水不漏
新朋友请关注「程序员联盟」微信搜公众号 ProgrammerLeague
程序员联盟官网:
coderunity点com
程序员联盟论坛:
coderunity点com/bbs/
小编微信号: frogoscar
小编邮箱: enmingx@gmail.com
【Linux探索之旅第三部分第二课:流、管道、重定向,三管齐下】
http://toutiao.com/a6193788933316428033/?iid=3041659310&app=news_article&tt_from=android_share&utm_medium=toutiao_android&utm_campaign=client_share
Dora RPC 虚拟机下实测性能
Php/Js/Shell/Go jackxiang 2015-9-14 11:31
背景:关于rpc,即远程过程调用,这个技术最早是由sun公司发明出来,后来在linux上默认有rpc服务,该功能我最早见在新浪的企业邮箱里有这样一个运用,在用户登录这块用到rpc,其服务端实现了与mysql长连接的技术,进而减少了重次重新连接,提高了高并发时的性能,而后来在鸟哥的一个php框架里实现了类似的php rpc框架,也是用c写的,但究其根源,还是来自于xdr这样一种数据结构,其可以跨平台使用,进而它在做一些高并发这块的的确确有较好的效果,最近rango兄弟的swoole里发布后,也有兄弟基于它做成了Dora Rpc,值得了解,应该性能还成,可能试用并使用,毕竟简单、效率、快才是王道。
Dora RPC
简介(Introduction)
用于复杂项目前后端分离,分离后项目都通过API工作可更好维护管理。
是一款基础于Swoole定长包头通讯协议的最精简的RPC
目前只提供PHP语言代码
后续有什么bug或者问题请提交Issue
功能支持(Function)
支持单API调用,多API并发调用
支持同步调用,异步任务下发
其他相关知识请参考Swoole扩展
客户端长链接,请求完毕后仍旧保留,减少握手消耗
guid收发一致性检测,避免发送和接收数据不一致
dora-rpc/server.php
使用最简单的方式实现的服务端
目前需要继承才能使用,继承后请实现dowork,这个函数是实际处理任务的函数参数为提交参数
做这个只是为了减少大家启用RPC的开发时间
返回结果是一个数组 分两部分,第一层是通讯状态(code),第二层是处理状态(code)
使用方法(Example)
客户端(Client)
服务端(Server)
_____________________________________________________________________________
经过24小时持续压力测试,目前接口仍旧工作正常
使用的vagrant虚拟进行压测的分配了1G内存和1核CPU(Mac 2.2 GHz Intel Core i7)
压测进程:目前只开了10个php进程疯狂发送请求
并发性能:TPS 2100上下(比直接使用curl快很多)
响应时间:0.02~0.04s 偶尔出现0.4s
后端代码为:查询一次数据库后返回结果
CPU使用:10~25%
内存使用:一个PHP task 16M 目前开了30个进程
PHP版本:5.4.41
压测时使用端口个数:10个(长连接)
测试代码使用的使用客户端示范程序无限循环,服务端直接返回一个数组。
每次接口会请求一次api接口调用后再下发一个请求内含两个并发任务
其他资源情况如下:
Dora <wbr>RPC <wbr>虚拟机下实测性能
此开源使用Swoole特性制作
客户端使用长链接,处理请求结束后连接也不会断开,再次使用的时候会自动找回
服务端自动管理task及进程通讯
通过task处理业务
如果使用更高速的序列化函数取代serialize会更快一些
支持单api请求,多api并发请求,此功能可取代发展越来越怪的gearman
如果有持久化请求需求,可以考虑在此基础上自行封装下(会降性能的哦)
过几天增加个中间件,可以检测后端服务压力状态自动负载均衡~
github地址
https://github.com/xcl3721/Dora-RPC
有一个哥们测试了一下,地址:http://blog.sina.com.cn/s/blog_54ef39890102vkgh.html
Dora RPC
简介(Introduction)
用于复杂项目前后端分离,分离后项目都通过API工作可更好维护管理。
是一款基础于Swoole定长包头通讯协议的最精简的RPC
目前只提供PHP语言代码
后续有什么bug或者问题请提交Issue
功能支持(Function)
支持单API调用,多API并发调用
支持同步调用,异步任务下发
其他相关知识请参考Swoole扩展
客户端长链接,请求完毕后仍旧保留,减少握手消耗
guid收发一致性检测,避免发送和接收数据不一致
dora-rpc/server.php
使用最简单的方式实现的服务端
目前需要继承才能使用,继承后请实现dowork,这个函数是实际处理任务的函数参数为提交参数
做这个只是为了减少大家启用RPC的开发时间
返回结果是一个数组 分两部分,第一层是通讯状态(code),第二层是处理状态(code)
使用方法(Example)
客户端(Client)
服务端(Server)
_____________________________________________________________________________
经过24小时持续压力测试,目前接口仍旧工作正常
使用的vagrant虚拟进行压测的分配了1G内存和1核CPU(Mac 2.2 GHz Intel Core i7)
压测进程:目前只开了10个php进程疯狂发送请求
并发性能:TPS 2100上下(比直接使用curl快很多)
响应时间:0.02~0.04s 偶尔出现0.4s
后端代码为:查询一次数据库后返回结果
CPU使用:10~25%
内存使用:一个PHP task 16M 目前开了30个进程
PHP版本:5.4.41
压测时使用端口个数:10个(长连接)
测试代码使用的使用客户端示范程序无限循环,服务端直接返回一个数组。
每次接口会请求一次api接口调用后再下发一个请求内含两个并发任务
其他资源情况如下:
Dora <wbr>RPC <wbr>虚拟机下实测性能
此开源使用Swoole特性制作
客户端使用长链接,处理请求结束后连接也不会断开,再次使用的时候会自动找回
服务端自动管理task及进程通讯
通过task处理业务
如果使用更高速的序列化函数取代serialize会更快一些
支持单api请求,多api并发请求,此功能可取代发展越来越怪的gearman
如果有持久化请求需求,可以考虑在此基础上自行封装下(会降性能的哦)
过几天增加个中间件,可以检测后端服务压力状态自动负载均衡~
github地址
https://github.com/xcl3721/Dora-RPC
有一个哥们测试了一下,地址:http://blog.sina.com.cn/s/blog_54ef39890102vkgh.html
PHP扩展相关信息及类函数如何查看,及内置函数参数怎么看的命令行查看办法备案。
Php/Js/Shell/Go jackxiang 2015-9-11 11:19
背景:有时需要查一些函数,比如分隔函数,不知道那个分割符号是放第几位了,怎么办? 有时想看php.ini文件在哪儿了,怎么办?有时想看这个扩展如:swoole扩展的相关扩展信息怎么看?有时想看这个扩展的类名怎么看?有时想看这个扩展的函数有哪些怎么了解,这些都是问题,于是有该文。
php -i ,php -i|grep php.ini php --ri swoole php --ri memcache
零)php -i|grep php.ini
[root@localhost htdocs]# php -i|grep php.ini
Configuration File (php.ini) Path => /usr/local/php/etc
Loaded Configuration File => /usr/local/php/etc/php.ini
--rf <name> Show information about function <name>.
--rc <name> Show information about class <name>.
--re <name> Show information about extension <name>.
--ri <name> Show configuration for extension <name>.
一)php --rf explode
[root@localhost htdocs]# php --rf explode
Function [ <internal:standard> function explode ] {
- Parameters [3] {
Parameter #0 [ <required> $separator ]
Parameter #1 [ <required> $str ]
Parameter #2 [ <optional> $limit ]
}
}
二)php --ri memcache
memcache
memcache support => enabled
Version => 3.0.6
Revision => $Revision: 310129 $
Directive => Local Value => Master Value
memcache.allow_failover => 1 => 1
memcache.max_failover_attempts => 20 => 20
memcache.default_port => 11211 => 11211
memcache.chunk_size => 32768 => 32768
memcache.protocol => ascii => ascii
memcache.hash_strategy => consistent => consistent
memcache.hash_function => crc32 => crc32
memcache.redundancy => 1 => 1
memcache.session_redundancy => 2 => 2
memcache.compress_threshold => 20000 => 20000
memcache.lock_timeout => 15 => 15
三)--re <name> Show information about extension <name>.
php --re memcache
Extension [ <persistent> extension #39 memcache version 3.0.6 ] {
Method [ <internal:memcache, inherits MemcachePool> public method decrement ] {
}
Method [ <internal:memcache, inherits MemcachePool> public method close ] {
}
Method [ <internal:memcache, inherits MemcachePool> public method flush ] {
}
}
四)--rc <name> Show information about class <name>.
php --rc memcache
Class [ <internal:memcache> class Memcache extends MemcachePool ] {
- Constants [0] {
}
php -i ,php -i|grep php.ini php --ri swoole php --ri memcache
零)php -i|grep php.ini
[root@localhost htdocs]# php -i|grep php.ini
Configuration File (php.ini) Path => /usr/local/php/etc
Loaded Configuration File => /usr/local/php/etc/php.ini
--rf <name> Show information about function <name>.
--rc <name> Show information about class <name>.
--re <name> Show information about extension <name>.
--ri <name> Show configuration for extension <name>.
一)php --rf explode
[root@localhost htdocs]# php --rf explode
Function [ <internal:standard> function explode ] {
- Parameters [3] {
Parameter #0 [ <required> $separator ]
Parameter #1 [ <required> $str ]
Parameter #2 [ <optional> $limit ]
}
}
二)php --ri memcache
memcache
memcache support => enabled
Version => 3.0.6
Revision => $Revision: 310129 $
Directive => Local Value => Master Value
memcache.allow_failover => 1 => 1
memcache.max_failover_attempts => 20 => 20
memcache.default_port => 11211 => 11211
memcache.chunk_size => 32768 => 32768
memcache.protocol => ascii => ascii
memcache.hash_strategy => consistent => consistent
memcache.hash_function => crc32 => crc32
memcache.redundancy => 1 => 1
memcache.session_redundancy => 2 => 2
memcache.compress_threshold => 20000 => 20000
memcache.lock_timeout => 15 => 15
三)--re <name> Show information about extension <name>.
php --re memcache
Extension [ <persistent> extension #39 memcache version 3.0.6 ] {
Method [ <internal:memcache, inherits MemcachePool> public method decrement ] {
}
Method [ <internal:memcache, inherits MemcachePool> public method close ] {
}
Method [ <internal:memcache, inherits MemcachePool> public method flush ] {
}
}
四)--rc <name> Show information about class <name>.
php --rc memcache
Class [ <internal:memcache> class Memcache extends MemcachePool ] {
- Constants [0] {
}
历史总是要通过这样决绝的悲情成就一段佳话,后来无数的传记这样记载那段故事,“1987年,任正非因为工作失误离开南油公司,被逼着走上了创业的道路。”
1987年,也是一个草莽英雄起家的年代。
1987年,宗庆后靠借来的14万元承包连年亏损的杭州上海校办企业经销部,并开始蹬三轮卖冰棍。1945年出生的宗庆后,这一年刚好42岁。
1987年,两个日后引领中国经济转折点的人一个刚从清华毕业,赶赴MIT攻读硕士学位。一个即将从杭州师范毕业。他们恰好都出生在1964年,这一年,他们都恰好是23岁。
去MIT的张朝阳遇见了尼葛洛庞帝,他们是最早投资中国互联网的人。杭州师范毕业的马云创办了海博翻译社,开始了曲折的试错过程。
1987年,44岁的任正非被迫辞职,离开了转业后分配到的南油公司。
是下面这段文字激发我研究1987年的深圳,1988年的中国和这两年的任正非。
“一个44岁老男人,经营中被骗了200万,被国企南油集团除名。曾求留任遭拒绝,还背负还清200万债。妻子又离婚,他一个人带着老爹老娘弟弟妹妹在深圳住棚屋,借钱创立了华为公司。已过了冲锋势头,没有资本、没有人脉、没有资源、没有技术、没有市场经验,看谁都比他强的一个人,逆袭成功。用27年把华为带到通讯行业世界第一位置。如果是你也有类似,今天你在哪里呢。”
我查了目前市面上的任正非传,基本上这段话的前半部分是有根据的。但后半部分有刻意曲解的成分。任正非当时是有一点点资本的,跟几个朋友一起创业也并非孤家寡人,他从南油退出时已经官至副总经理。而且他处在管制最为宽松的深圳,当时他跟王石一样,靠倒卖产品差价获得第一桶金。而且他们都赶上深圳最适合创业的年代,1988年,那不过是中国的“五月花号”把全中国最不安分的人都带到了这个国境线最南端的小渔港的时候。
为了说明一个人的传奇其实并不必附会他的苦难过去,并非苦难越多越能衬托一个人的成功意义。
44岁的任正非,并不比70多的褚时健缺乏励志性,那些触底反弹的故事只要让人们明白触底不一定会跟着反弹就够了,而不用一直强调底有多深多长。
任何人,如果灾难足够长,困难足够多,命运足够惨一定是可以被打倒的,所谓活下来的人,三分之一靠努力,三分之一靠人品,三分之一靠运气,概莫能外,缺一不可。后代人写历史,不应老盯着人的意志和主观能动性,这会教坏年轻人,因为大部分走投无路的成功说到底不过是靠了运气之手在背后推了一把而已。
若成功太容易,它的深刻性和参考性就可能不足。同样是成功者,陈天桥和史玉柱可能恰好只是在对的时间抓住了对的行业。“恰好”是统计学里的概率问题,不可能人人学会。
倒是任正非这种不屈服和不放弃能成为年轻人的精神动力。所谓雄关漫道真如铁,而今迈步从头越,每一个有追求但身陷囹圄的年轻人,在最无助的时候想想任正非,你应该还没有他那么惨吧,至少你还有青春,还有宽松的社会环境,还有再来一次的可能。
相信历史总不缺乏再一次的巧合,只是到那个时候,能不能问自己一句,在那个波澜壮阔的年份,当时的你在哪里?跟谁风云际会?
摘自:http://www.cfi.net.cn/p20150908000864.html
1987年,也是一个草莽英雄起家的年代。
1987年,宗庆后靠借来的14万元承包连年亏损的杭州上海校办企业经销部,并开始蹬三轮卖冰棍。1945年出生的宗庆后,这一年刚好42岁。
1987年,两个日后引领中国经济转折点的人一个刚从清华毕业,赶赴MIT攻读硕士学位。一个即将从杭州师范毕业。他们恰好都出生在1964年,这一年,他们都恰好是23岁。
去MIT的张朝阳遇见了尼葛洛庞帝,他们是最早投资中国互联网的人。杭州师范毕业的马云创办了海博翻译社,开始了曲折的试错过程。
1987年,44岁的任正非被迫辞职,离开了转业后分配到的南油公司。
是下面这段文字激发我研究1987年的深圳,1988年的中国和这两年的任正非。
“一个44岁老男人,经营中被骗了200万,被国企南油集团除名。曾求留任遭拒绝,还背负还清200万债。妻子又离婚,他一个人带着老爹老娘弟弟妹妹在深圳住棚屋,借钱创立了华为公司。已过了冲锋势头,没有资本、没有人脉、没有资源、没有技术、没有市场经验,看谁都比他强的一个人,逆袭成功。用27年把华为带到通讯行业世界第一位置。如果是你也有类似,今天你在哪里呢。”
我查了目前市面上的任正非传,基本上这段话的前半部分是有根据的。但后半部分有刻意曲解的成分。任正非当时是有一点点资本的,跟几个朋友一起创业也并非孤家寡人,他从南油退出时已经官至副总经理。而且他处在管制最为宽松的深圳,当时他跟王石一样,靠倒卖产品差价获得第一桶金。而且他们都赶上深圳最适合创业的年代,1988年,那不过是中国的“五月花号”把全中国最不安分的人都带到了这个国境线最南端的小渔港的时候。
为了说明一个人的传奇其实并不必附会他的苦难过去,并非苦难越多越能衬托一个人的成功意义。
44岁的任正非,并不比70多的褚时健缺乏励志性,那些触底反弹的故事只要让人们明白触底不一定会跟着反弹就够了,而不用一直强调底有多深多长。
任何人,如果灾难足够长,困难足够多,命运足够惨一定是可以被打倒的,所谓活下来的人,三分之一靠努力,三分之一靠人品,三分之一靠运气,概莫能外,缺一不可。后代人写历史,不应老盯着人的意志和主观能动性,这会教坏年轻人,因为大部分走投无路的成功说到底不过是靠了运气之手在背后推了一把而已。
若成功太容易,它的深刻性和参考性就可能不足。同样是成功者,陈天桥和史玉柱可能恰好只是在对的时间抓住了对的行业。“恰好”是统计学里的概率问题,不可能人人学会。
倒是任正非这种不屈服和不放弃能成为年轻人的精神动力。所谓雄关漫道真如铁,而今迈步从头越,每一个有追求但身陷囹圄的年轻人,在最无助的时候想想任正非,你应该还没有他那么惨吧,至少你还有青春,还有宽松的社会环境,还有再来一次的可能。
相信历史总不缺乏再一次的巧合,只是到那个时候,能不能问自己一句,在那个波澜壮阔的年份,当时的你在哪里?跟谁风云际会?
摘自:http://www.cfi.net.cn/p20150908000864.html
背景:转这个哥们的文章有两点:1)他的博客和我的样式几乎一样,有缘分。2)现在移动互联网如火如荼,虚火很大,很多人都往里面钻,但真正懂用户懂产品技术的还是少,这个哥们的语言有点调侃,描绘生动,心理活动也很丰富,集合现实的一些人情关系的描写,跃然纸上,转了吧。
这是一个“如有雷同,纯属巧合”的故事,外加一些废话,大家请勿对号入座。开始了……
我有些尴尬地拿着水杯,正对面坐着来访的王总,他是在别处打拼的人,这几年据说收获颇丰,见移动互联网如火如荼,自然也想着要进来干一场,尽管王总从事的行当也算跟IT沾边,但毕竟太长时间不接触技术,有些东西不太熟,总要咨询下我这个在一线开发混了十几年的老程序员,十几年的开发,有好几种可能性,不过这不是重点,所以暂时忽略掉这个细节吧。
我之所以尴尬,是对王总的需求有些不知如何回答,仿佛陷入了某种习惯性的沉思中。
王总站了起来,把手机递到我面前,说:“你看看,就这样一个APP。”他不太熟练地在屏幕上划了几下,我并没有很认真地看,因为我知道这个问题很难,那就是所有的开发者都会被问,并且可能是被问得最频的一个问题:“开发这么一个APP需要多长时间?”我很想说不知道,这可能是最直截了当和准确的回答,但面对王总这位老朋友,我要是这么回答估计有些失礼,所以这个时候,我除了大致思量了一下他所指的那个APP大致涉及到哪些方面之外,还要组织下自己的语言,如何用非常得体的话告诉他,这个事情我估算不出。“你看,就这么简单的一个APP”,王总继续在屏幕上拨弄了几下,然后带着几分期待的眼神看着我。
我谨慎地说:“坦白说,我说不准,我这方面经验也不是很足,尽管做过APP开发,但又跟这个很不一样,得具体分析好所有的逻辑,才能估算出时间。”
王总对我的说法似乎不以为然,他晃了晃手机,说:“我要求不多,其实比这个还简单”,他指着屏幕上某些地方,继续说:“这个,这个,这个都可以不要,只需要这么一个列表,里面有详情,可以查看修改……”
我心里很自然地想到这是很典型的“想当然简单”的态度,我想我得让他认识到这个问题的复杂程度,我反问道:“需要登录吗?”
王总稍作停顿后,说:“那当然。”
“什么登录?用户名密码方式,还是手机登录,抑或像QQ,微博,微信这种可以借用的第三方登录?”
王总这回似乎想了一下:“作为移动互联网,我想手机登录肯定是要的,QQ,微博,对了,微信,微信最好也要……哦,你前面说用户名密码,这个应该也是要的吧。”
我很流利地接着问:“那总得有注册,如果你打算用手机登录,那得找个短信平台,还有微信登录,你得先做好企业身份认证,对了,有登录,有密码,那密码找回功能也得有吧。”
“这是肯定的。”
“同时有多种登录途径,你必须要想出一种合理的逻辑来将它们‘整合’,最常见的当然是账号绑定,例如给你的账号绑定手机号码,这样就能用手机号来登录同样一个账号,对微信登录也同理,但如今移动互联网的用户们都挺厌恶注册流程的,所以往往会要求直接手机登录或者直接微信登录,自动完成注册过程,那考虑这种情况,如果用户先用微信登录,然后再用手机登录,而不是绑定,那么就会产生两个不同的账号,而且无法将其再‘整合’起来,我们得想出一套比较完善的方案……”
王总对我所说的似乎有些缺乏耐心:“没必要这么复杂吧?你看看这个APP,这些不都有吗?”
“有没有我前面所描述的那个问题,你尝试过了吗?”
但王总似乎对问题并不关心,他只想知道做这么一个APP需要多长时间,当然要多少钱,这也是他关心的问题,他拿出了信心满满的语气:“有问题怕什么?困难算什么?这些我相信都能解决,但时间很要紧,得快,我们的竞争对手不会等我们,就这么一个东西,你想想看,要多久?”
看他的架势,像十足那种混得风生水起的成功人士,而我这种身份低微的程序员在他面前确实是有口难言,我本来还想继续告诉他细节的重要性,却被他打断:“不,不需要有多精确,你只需要估算一个范围,两个星期?或是两个月?”
我觉得我没必要再隐瞒什么了:“我真的不知道,也许一支优秀的团队两个星期就能做好(不过我自己可不相信有这么牛逼的团队),但我很明显不是那个能创造这种奇迹的人。”我心想其实就算说出了“两个星期到两年”这么一个开玩笑式的范围,也可能是错的。
王总似乎对我这样的回答很失望。但他是个执行力很强的人,想做一件事,就一定会行动,行动一定快,一定要有结果,这种雷厉风行的行事风格,确实,我挺欣赏,不过他的这个项目,我可真帮不上忙,但我还是出于礼貌,说道:“技术方面有什么问题,还是可以来问我的。”
====================== 不怎么华丽的分隔线 ======================
“做一个APP需要多长时间?”这个问题估计比测一个人还能活几天还难,一个条件如此不充分的问题,如何回答呢?
总体来说,需求越是明确,团队越是成熟,估算出来的时间就越是准确。而软件开发这个事情,不管发展多少年,不管提出了怎样的方法论,都没办法像传统制造业那样把“工时”算得那么精确,其内部错综复杂的逻辑关系使然,软件工程,绝无可能量产。
用户看到的只是一个APP,如果他用的是iOS系统,也许他根本就不会接触Android,不知道开发者除了iOS版之外,还需要做一个Android版,(有没可能还有Windows版?这样工作量无疑更大)或者,网页版搞定一切?也许你真正动手做过后就不会这么认为,再说微信小店那种模式真能适用于所有场合么?而且,如果不是网络出现异常的话,一般用户也不会注意到服务器的存在,服务器总是那么默默无闻地为用户全天候地工作,它的开发难度恐怕也不亚于APP本身,而负责APP运维的还需一些人力,大了之后甚至需要组建一个专业团队,他们需要一个“后台”,能随时查看和处理数据,如果需要随时随地都能查看和处理数据,恐怕还得给后台专门弄个APP。
这个道理就有点类似:我们看到了战机在天上华丽地完成了歼敌任务,以为只是战机本身很牛,往往忽视了战机相关的那些配套,如果没有娴熟的飞行员、作战指挥中心、地面雷达、预警机、补给、机场或航母、地勤人员等等,那么战机将失去战斗力。APP也一样,它不是一个只要能跑起来就完事的东西,支持它的配套设施和维护工作丝毫不比APP本身简单。
除开这些大的方面,细节上也带有许多的不确定性,所以一支成熟的团队尤为重要,一个经验丰富的开发者会知道,至少大致知道这个开发过程会遇到哪些问题,哪些问题比较简单,哪些问题则可能需要耗费大量的时间,这得依赖经验。我有一句话常常挂在嘴边,那就是:“没做过的东西别轻易说简单。”“想当然简单”的态度对项目没有任何好处,如果自己不确定,那么去咨询一个有这方面经验的人,就算得不到具体的答案也有大致的方向,沿着这些方向研究一下,就能知道会面临的那些问题,当然往往还不是全部。
关于“低估了难度”这事情,我过去的公司有个经典故事,当时有个小项目,就是准备把一套已经在仪器上使用的只支持英语的程序增加多语言支持,程序并不大,涉及内容也不算太多,工程师一开始认为这只是个简单的翻译工作,顶多两个星期就能完成,但一做下去就发现不简单,首先翻译得找专业人士来做,自己做不好,我们没人精通欧洲各国语言,接下来还有单位换算,有些国家用公制,有些用英制,这个得考虑,包括日期显示格式也得考虑,一下子不知道多了多少工作,这些都差不多了之后又发现了德语单词过长,我们的仪器的屏幕显示不下,超出范围,于是再调字体,做精简,前前后后开会讨论了N次,最后想Release的时候发现这么一改,程序的Size变大了很多,有些仪器的存储器装不下,这下大家可都傻了,优化呗,精简呗,程序开始有些凌乱不堪了,最后勉强通过质控部检验,总算发布了,发觉足足搞了半年。不过如今想想之所以耗费了这么多时间,一个很重要的原因是经验不足,对多语言,国际化这块不熟,走了不少弯路,所以我前面也提到,成熟的团队尤为重要。
我们在估算项目时间的时候,往往只算了“写代码的时间”,而把那些和老板或客户扯皮,做需求分析,设计,测试,和修复bug的时间不考虑进去,而这些时间加起来通常比写代码的时间多出不少,我个人是不轻易为了讨好老板而把完成时间说得很短的,为啥?——根本做不到嘛,干嘛要撒谎?如果一个需要一星期完成的新功能开发,我通常得把这个时间double,这已经算比较“不保守”的了。
即便只算写代码的时间,也往往会被低估,老板或客户对你开发的东西很可能不满意,或许你误解了他的功能需求,或者界面有点卡顿,或者这个图标颜色不好看,你是开发者,不是美工,虽然凑合可以当一下美工,但毕竟不专业,更重要的是做做UI设计,做做图这种事情,也得耗费不少时间,当你为“一个像素”焦头烂额的时候,是不是很渴望团队中有一名设计师?这时候得提醒下老板:你必须要在时间和功能之间,做点取舍。老板当然很不高兴,但也不得不在功能上做出了一些妥协。虽然这样做能让难产的项目早点上线,但却为来日项目的失败,给老板添加了一个很好的借口:我们的工程师太差了,没按我说的去做。
老板或客户除了会抱怨你做出来的东西不够好看之外,还会再提很多东西:这个界面能不能改成多选,能否增加通知功能,已读未读状态要有,界面能不能再流畅点,昨晚程序咋“闪退”了一次……需求只管提功能,但没说具体这个UI要多美观,也没说程序稳定性要好,更没涉及到要达到多大的吞吐量,当然,可能更重要的——安全性也没提,你心一惊:是啊,如果有黑客,不,只要稍微懂一点技术的恶意用户想刷爆我们的服务器,那简直太简单了,而这些防护措施我都没做!所幸的是项目名气太小,暂时无需考虑这个。(貌似大多数APP都活不到需要考虑这个的时候)
所有这些,你说功能也好,细节也好,稳健性也好,都不是能自动从土里长出来的东西,都得需要花时间去想,去做,有些甚至还是个“系统工程”,如果头痛医头脚痛医脚去做的话,系统里到处充满“飞线”,无疑会给将来的维护留下了许多隐患。攻城狮的你,都考虑了吗?更别说老板为了节省成本而给你购置的低性能电脑让你整天抓狂这些“无关紧要”的事。
====================== 不怎么华丽的分隔线 ======================
话说王总告别我之后就以迅雷不及掩耳之势注册了公司,注册了域名,搞到了办公室,还一下子叫来了一帮子人风风火火地搞了起来,这种发展势头,这种干劲,我只有自叹不如。心底里真有些后悔怎么没跟他去干事业,不过这只是感性的一瞬间,理性又在接下来的几百毫秒里将我拉了回来:还是别去好,跟他沟通不来的。
王总的项目后来以一飞冲天之势迅猛发展,而他如今已经是一家估值几亿的公司的CEO,我嘛,越来越觉得自己是个Loser,独自坐在办公室里,还是拿着那个水杯,懊恼不已——打住!这样是不是比较有戏剧性?可虽然一开始我就声明此故事“如有雷同,纯属巧合”,但也不能胡乱瞎编,真正的结局是:确实风风火火弄了几个月,后来就突然杳无音讯了,本来想打电话问问王总究竟怎样,无奈他变成了另一个超级忙人,再无心思跟我聊家常了。嗯,结局还是差不多,我还是那个继续苦逼地坐在办公室里的程序员,唉,别想了,开工吧!
原文原创来自:http://www.cnblogs.com/guogangj/p/4676836.html
这是一个“如有雷同,纯属巧合”的故事,外加一些废话,大家请勿对号入座。开始了……
我有些尴尬地拿着水杯,正对面坐着来访的王总,他是在别处打拼的人,这几年据说收获颇丰,见移动互联网如火如荼,自然也想着要进来干一场,尽管王总从事的行当也算跟IT沾边,但毕竟太长时间不接触技术,有些东西不太熟,总要咨询下我这个在一线开发混了十几年的老程序员,十几年的开发,有好几种可能性,不过这不是重点,所以暂时忽略掉这个细节吧。
我之所以尴尬,是对王总的需求有些不知如何回答,仿佛陷入了某种习惯性的沉思中。
王总站了起来,把手机递到我面前,说:“你看看,就这样一个APP。”他不太熟练地在屏幕上划了几下,我并没有很认真地看,因为我知道这个问题很难,那就是所有的开发者都会被问,并且可能是被问得最频的一个问题:“开发这么一个APP需要多长时间?”我很想说不知道,这可能是最直截了当和准确的回答,但面对王总这位老朋友,我要是这么回答估计有些失礼,所以这个时候,我除了大致思量了一下他所指的那个APP大致涉及到哪些方面之外,还要组织下自己的语言,如何用非常得体的话告诉他,这个事情我估算不出。“你看,就这么简单的一个APP”,王总继续在屏幕上拨弄了几下,然后带着几分期待的眼神看着我。
我谨慎地说:“坦白说,我说不准,我这方面经验也不是很足,尽管做过APP开发,但又跟这个很不一样,得具体分析好所有的逻辑,才能估算出时间。”
王总对我的说法似乎不以为然,他晃了晃手机,说:“我要求不多,其实比这个还简单”,他指着屏幕上某些地方,继续说:“这个,这个,这个都可以不要,只需要这么一个列表,里面有详情,可以查看修改……”
我心里很自然地想到这是很典型的“想当然简单”的态度,我想我得让他认识到这个问题的复杂程度,我反问道:“需要登录吗?”
王总稍作停顿后,说:“那当然。”
“什么登录?用户名密码方式,还是手机登录,抑或像QQ,微博,微信这种可以借用的第三方登录?”
王总这回似乎想了一下:“作为移动互联网,我想手机登录肯定是要的,QQ,微博,对了,微信,微信最好也要……哦,你前面说用户名密码,这个应该也是要的吧。”
我很流利地接着问:“那总得有注册,如果你打算用手机登录,那得找个短信平台,还有微信登录,你得先做好企业身份认证,对了,有登录,有密码,那密码找回功能也得有吧。”
“这是肯定的。”
“同时有多种登录途径,你必须要想出一种合理的逻辑来将它们‘整合’,最常见的当然是账号绑定,例如给你的账号绑定手机号码,这样就能用手机号来登录同样一个账号,对微信登录也同理,但如今移动互联网的用户们都挺厌恶注册流程的,所以往往会要求直接手机登录或者直接微信登录,自动完成注册过程,那考虑这种情况,如果用户先用微信登录,然后再用手机登录,而不是绑定,那么就会产生两个不同的账号,而且无法将其再‘整合’起来,我们得想出一套比较完善的方案……”
王总对我所说的似乎有些缺乏耐心:“没必要这么复杂吧?你看看这个APP,这些不都有吗?”
“有没有我前面所描述的那个问题,你尝试过了吗?”
但王总似乎对问题并不关心,他只想知道做这么一个APP需要多长时间,当然要多少钱,这也是他关心的问题,他拿出了信心满满的语气:“有问题怕什么?困难算什么?这些我相信都能解决,但时间很要紧,得快,我们的竞争对手不会等我们,就这么一个东西,你想想看,要多久?”
看他的架势,像十足那种混得风生水起的成功人士,而我这种身份低微的程序员在他面前确实是有口难言,我本来还想继续告诉他细节的重要性,却被他打断:“不,不需要有多精确,你只需要估算一个范围,两个星期?或是两个月?”
我觉得我没必要再隐瞒什么了:“我真的不知道,也许一支优秀的团队两个星期就能做好(不过我自己可不相信有这么牛逼的团队),但我很明显不是那个能创造这种奇迹的人。”我心想其实就算说出了“两个星期到两年”这么一个开玩笑式的范围,也可能是错的。
王总似乎对我这样的回答很失望。但他是个执行力很强的人,想做一件事,就一定会行动,行动一定快,一定要有结果,这种雷厉风行的行事风格,确实,我挺欣赏,不过他的这个项目,我可真帮不上忙,但我还是出于礼貌,说道:“技术方面有什么问题,还是可以来问我的。”
====================== 不怎么华丽的分隔线 ======================
“做一个APP需要多长时间?”这个问题估计比测一个人还能活几天还难,一个条件如此不充分的问题,如何回答呢?
总体来说,需求越是明确,团队越是成熟,估算出来的时间就越是准确。而软件开发这个事情,不管发展多少年,不管提出了怎样的方法论,都没办法像传统制造业那样把“工时”算得那么精确,其内部错综复杂的逻辑关系使然,软件工程,绝无可能量产。
用户看到的只是一个APP,如果他用的是iOS系统,也许他根本就不会接触Android,不知道开发者除了iOS版之外,还需要做一个Android版,(有没可能还有Windows版?这样工作量无疑更大)或者,网页版搞定一切?也许你真正动手做过后就不会这么认为,再说微信小店那种模式真能适用于所有场合么?而且,如果不是网络出现异常的话,一般用户也不会注意到服务器的存在,服务器总是那么默默无闻地为用户全天候地工作,它的开发难度恐怕也不亚于APP本身,而负责APP运维的还需一些人力,大了之后甚至需要组建一个专业团队,他们需要一个“后台”,能随时查看和处理数据,如果需要随时随地都能查看和处理数据,恐怕还得给后台专门弄个APP。
这个道理就有点类似:我们看到了战机在天上华丽地完成了歼敌任务,以为只是战机本身很牛,往往忽视了战机相关的那些配套,如果没有娴熟的飞行员、作战指挥中心、地面雷达、预警机、补给、机场或航母、地勤人员等等,那么战机将失去战斗力。APP也一样,它不是一个只要能跑起来就完事的东西,支持它的配套设施和维护工作丝毫不比APP本身简单。
除开这些大的方面,细节上也带有许多的不确定性,所以一支成熟的团队尤为重要,一个经验丰富的开发者会知道,至少大致知道这个开发过程会遇到哪些问题,哪些问题比较简单,哪些问题则可能需要耗费大量的时间,这得依赖经验。我有一句话常常挂在嘴边,那就是:“没做过的东西别轻易说简单。”“想当然简单”的态度对项目没有任何好处,如果自己不确定,那么去咨询一个有这方面经验的人,就算得不到具体的答案也有大致的方向,沿着这些方向研究一下,就能知道会面临的那些问题,当然往往还不是全部。
关于“低估了难度”这事情,我过去的公司有个经典故事,当时有个小项目,就是准备把一套已经在仪器上使用的只支持英语的程序增加多语言支持,程序并不大,涉及内容也不算太多,工程师一开始认为这只是个简单的翻译工作,顶多两个星期就能完成,但一做下去就发现不简单,首先翻译得找专业人士来做,自己做不好,我们没人精通欧洲各国语言,接下来还有单位换算,有些国家用公制,有些用英制,这个得考虑,包括日期显示格式也得考虑,一下子不知道多了多少工作,这些都差不多了之后又发现了德语单词过长,我们的仪器的屏幕显示不下,超出范围,于是再调字体,做精简,前前后后开会讨论了N次,最后想Release的时候发现这么一改,程序的Size变大了很多,有些仪器的存储器装不下,这下大家可都傻了,优化呗,精简呗,程序开始有些凌乱不堪了,最后勉强通过质控部检验,总算发布了,发觉足足搞了半年。不过如今想想之所以耗费了这么多时间,一个很重要的原因是经验不足,对多语言,国际化这块不熟,走了不少弯路,所以我前面也提到,成熟的团队尤为重要。
我们在估算项目时间的时候,往往只算了“写代码的时间”,而把那些和老板或客户扯皮,做需求分析,设计,测试,和修复bug的时间不考虑进去,而这些时间加起来通常比写代码的时间多出不少,我个人是不轻易为了讨好老板而把完成时间说得很短的,为啥?——根本做不到嘛,干嘛要撒谎?如果一个需要一星期完成的新功能开发,我通常得把这个时间double,这已经算比较“不保守”的了。
即便只算写代码的时间,也往往会被低估,老板或客户对你开发的东西很可能不满意,或许你误解了他的功能需求,或者界面有点卡顿,或者这个图标颜色不好看,你是开发者,不是美工,虽然凑合可以当一下美工,但毕竟不专业,更重要的是做做UI设计,做做图这种事情,也得耗费不少时间,当你为“一个像素”焦头烂额的时候,是不是很渴望团队中有一名设计师?这时候得提醒下老板:你必须要在时间和功能之间,做点取舍。老板当然很不高兴,但也不得不在功能上做出了一些妥协。虽然这样做能让难产的项目早点上线,但却为来日项目的失败,给老板添加了一个很好的借口:我们的工程师太差了,没按我说的去做。
老板或客户除了会抱怨你做出来的东西不够好看之外,还会再提很多东西:这个界面能不能改成多选,能否增加通知功能,已读未读状态要有,界面能不能再流畅点,昨晚程序咋“闪退”了一次……需求只管提功能,但没说具体这个UI要多美观,也没说程序稳定性要好,更没涉及到要达到多大的吞吐量,当然,可能更重要的——安全性也没提,你心一惊:是啊,如果有黑客,不,只要稍微懂一点技术的恶意用户想刷爆我们的服务器,那简直太简单了,而这些防护措施我都没做!所幸的是项目名气太小,暂时无需考虑这个。(貌似大多数APP都活不到需要考虑这个的时候)
所有这些,你说功能也好,细节也好,稳健性也好,都不是能自动从土里长出来的东西,都得需要花时间去想,去做,有些甚至还是个“系统工程”,如果头痛医头脚痛医脚去做的话,系统里到处充满“飞线”,无疑会给将来的维护留下了许多隐患。攻城狮的你,都考虑了吗?更别说老板为了节省成本而给你购置的低性能电脑让你整天抓狂这些“无关紧要”的事。
====================== 不怎么华丽的分隔线 ======================
话说王总告别我之后就以迅雷不及掩耳之势注册了公司,注册了域名,搞到了办公室,还一下子叫来了一帮子人风风火火地搞了起来,这种发展势头,这种干劲,我只有自叹不如。心底里真有些后悔怎么没跟他去干事业,不过这只是感性的一瞬间,理性又在接下来的几百毫秒里将我拉了回来:还是别去好,跟他沟通不来的。
王总的项目后来以一飞冲天之势迅猛发展,而他如今已经是一家估值几亿的公司的CEO,我嘛,越来越觉得自己是个Loser,独自坐在办公室里,还是拿着那个水杯,懊恼不已——打住!这样是不是比较有戏剧性?可虽然一开始我就声明此故事“如有雷同,纯属巧合”,但也不能胡乱瞎编,真正的结局是:确实风风火火弄了几个月,后来就突然杳无音讯了,本来想打电话问问王总究竟怎样,无奈他变成了另一个超级忙人,再无心思跟我聊家常了。嗯,结局还是差不多,我还是那个继续苦逼地坐在办公室里的程序员,唉,别想了,开工吧!
原文原创来自:http://www.cnblogs.com/guogangj/p/4676836.html
背景:这位兄弟做的lnmp包细节上不错,不支持hhvm,最主要是这位兄弟其服务意识好,之前有一个lnmp.org,我觉得都挺不错,这块主要是对nginx代码了apache后,apache如何获取ip这块是个大问题,需要一些模块来设置的一个配置,对来源IP有一个日志需求很正常,这块像Tencent的TGW,其实在这一块从一个大的IP进来分到后面的机器处理,到底落到哪台机器了,及IP是多少,也涉及到这些类似问题,对于此种架构来讲,没有过实际生产经验,仅供参考,一般直接从硬件如F5,或lvs代理到apache或nginx,我想这个哥们的应用场景可能不大一样吧。
Internet -> Nginx -> Apache
最近在将Apache-2.2和Apache-2.4添加到《lnmp一键安装包》中,Nginx作为前端,Apache作为后端的情况下,Apache只能获取到Nginx前端的ip地址(127.0.0.1),而无法获取到用户的真实ip地址,在这种情况下,后端是Apache如何获取用户真实IP地址?
Nginx配置如下:
location / {
try_files $uri @apache;
}
location @apache {
internal;
proxy_pass http://127.0.0.1:8080;
include proxy.conf;
}
location ~ .*\.(php|php5)?$ {
proxy_pass http://127.0.0.1:8080;
include proxy.conf;
}
proxy_connect_timeout 300s;
proxy_send_timeout 900;
proxy_read_timeout 900;
proxy_buffer_size 32k;
proxy_buffers 4 64k;
proxy_busy_buffers_size 128k;
proxy_redirect off;
proxy_hide_header Vary;
proxy_set_header Accept-Encoding '';
proxy_set_header Referer $http_referer;
proxy_set_header Cookie $http_cookie;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
获取真实IP地址有Apache有2个模块:
mod_rpaf:Apache-2.2支持;Apache-2.4不支持。网上教程很多
mod_remoteip:Apache-2.4自带模块;Apache-2.2支持;推荐
Apache-2.2.25
mod_rpaf模块
wget http://stderr.net/apache/rpaf/download/mod_rpaf-0.6.tar.gz
tar -xzvf mod_rpaf-0.6.tar.gz
cd mod_rpaf-0.6/
/usr/local/apache/bin/apxs -i -c -n mod_rpaf-2.0.slo mod_rpaf-2.0.c
添加Apache配置
vi /usr/local/apache/conf/httpd.conf
Include conf/extra/httpd-rpaf.conf
vi /usr/local/apache/conf/extra/httpd-rpaf.conf
LoadModule rpaf_module modules/mod_rpaf-2.0.so
RPAFenable On
RPAFsethostname On
RPAFproxy_ips 127.0.0.1 10.8.0.110 # 代理服务器的ip地址(记得做相应修改)
RPAFheader X-Forwarded-For
备注:RPAFproxy_ips后面添加代理服务器的ip地址,有几个填几个
测试
# /usr/local/apache/bin/apachectl -t
# /usr/local/apache/bin/apachectl restart
# 看日志
mod_remoteip
Apache-2.2下配置mod_remoteip如下:
安装
wget https://github.com/ttkzw/mod_remoteip-httpd22/raw/master/mod_remoteip.c
/usr/local/apache/bin/apxs -i -c -n mod_remoteip.so mod_remoteip.c
修改配置文件:
vi /usr/local/apache/conf/httpd.conf
Include conf/extra/httpd-remoteip.conf
vi /usr/local/apache/conf/extra/httpd-remoteip.conf
LoadModule remoteip_module modules/mod_remoteip.so
RemoteIPHeader X-Forwarded-For
RemoteIPInternalProxy 127.0.0.1
测试:
# /usr/local/apache/bin/apachectl -t
# /usr/local/apache/bin/apachectl restart
# 看日志
Apache-2.4配置mod_remoteip除了上面(自带mod_remoteip模块不需要安装),还需要修改日志格式(折腾很久)
LogFormat "%h %a %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %a %l %u %t \"%r\" %>s %b" common
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedi
在日志格式中加上%a
摘自:https://blog.linuxeye.com/378.html
Q:这里是老大的教程,但最后有一个修改日志格式的教程,请问日志格式在哪修改,文件路径是什么啊?
那最后面 Apache-2.4配置mod_remoteip除了上面(自带mod_remoteip模块不需要安装),还需要修改日志格式(折腾很久),这里的日志格式在哪里修改呢,谢谢?
A:请看这文章:http://blog.sina.com.cn/s/blog_672c5a470100xj7z.html
Internet -> Nginx -> Apache
最近在将Apache-2.2和Apache-2.4添加到《lnmp一键安装包》中,Nginx作为前端,Apache作为后端的情况下,Apache只能获取到Nginx前端的ip地址(127.0.0.1),而无法获取到用户的真实ip地址,在这种情况下,后端是Apache如何获取用户真实IP地址?
Nginx配置如下:
location / {
try_files $uri @apache;
}
location @apache {
internal;
proxy_pass http://127.0.0.1:8080;
include proxy.conf;
}
location ~ .*\.(php|php5)?$ {
proxy_pass http://127.0.0.1:8080;
include proxy.conf;
}
proxy_connect_timeout 300s;
proxy_send_timeout 900;
proxy_read_timeout 900;
proxy_buffer_size 32k;
proxy_buffers 4 64k;
proxy_busy_buffers_size 128k;
proxy_redirect off;
proxy_hide_header Vary;
proxy_set_header Accept-Encoding '';
proxy_set_header Referer $http_referer;
proxy_set_header Cookie $http_cookie;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
获取真实IP地址有Apache有2个模块:
mod_rpaf:Apache-2.2支持;Apache-2.4不支持。网上教程很多
mod_remoteip:Apache-2.4自带模块;Apache-2.2支持;推荐
Apache-2.2.25
mod_rpaf模块
wget http://stderr.net/apache/rpaf/download/mod_rpaf-0.6.tar.gz
tar -xzvf mod_rpaf-0.6.tar.gz
cd mod_rpaf-0.6/
/usr/local/apache/bin/apxs -i -c -n mod_rpaf-2.0.slo mod_rpaf-2.0.c
添加Apache配置
vi /usr/local/apache/conf/httpd.conf
Include conf/extra/httpd-rpaf.conf
vi /usr/local/apache/conf/extra/httpd-rpaf.conf
LoadModule rpaf_module modules/mod_rpaf-2.0.so
RPAFenable On
RPAFsethostname On
RPAFproxy_ips 127.0.0.1 10.8.0.110 # 代理服务器的ip地址(记得做相应修改)
RPAFheader X-Forwarded-For
备注:RPAFproxy_ips后面添加代理服务器的ip地址,有几个填几个
测试
# /usr/local/apache/bin/apachectl -t
# /usr/local/apache/bin/apachectl restart
# 看日志
mod_remoteip
Apache-2.2下配置mod_remoteip如下:
安装
wget https://github.com/ttkzw/mod_remoteip-httpd22/raw/master/mod_remoteip.c
/usr/local/apache/bin/apxs -i -c -n mod_remoteip.so mod_remoteip.c
修改配置文件:
vi /usr/local/apache/conf/httpd.conf
Include conf/extra/httpd-remoteip.conf
vi /usr/local/apache/conf/extra/httpd-remoteip.conf
LoadModule remoteip_module modules/mod_remoteip.so
RemoteIPHeader X-Forwarded-For
RemoteIPInternalProxy 127.0.0.1
测试:
# /usr/local/apache/bin/apachectl -t
# /usr/local/apache/bin/apachectl restart
# 看日志
Apache-2.4配置mod_remoteip除了上面(自带mod_remoteip模块不需要安装),还需要修改日志格式(折腾很久)
LogFormat "%h %a %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %a %l %u %t \"%r\" %>s %b" common
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedi
在日志格式中加上%a
摘自:https://blog.linuxeye.com/378.html
Q:这里是老大的教程,但最后有一个修改日志格式的教程,请问日志格式在哪修改,文件路径是什么啊?
那最后面 Apache-2.4配置mod_remoteip除了上面(自带mod_remoteip模块不需要安装),还需要修改日志格式(折腾很久),这里的日志格式在哪里修改呢,谢谢?
A:请看这文章:http://blog.sina.com.cn/s/blog_672c5a470100xj7z.html
内核参数调整消息队列设置
Unix/LinuxC技术 jackxiang 2015-9-6 16:47
背景:想要做一个高性能的框架也好,其实还是站在内核上面跳舞,为此,其对内核的设置很重要,就以swoole来讲,其queque是基于epoll,进程间通讯用到内核的que,当然要设置它 了,再就是消息队列这块的通讯,是不是也得设置,这块还有高并发的句柄这块,也需要设置为更大。这块linux下的epoll和freebsd的kqueque都要设置一下,否则,用不上内核的能力也就问题大了,swoole的nginx配置到swoole的通讯用unix socket dgram,也需要配置,你可能说这个框架性能不行了,其实性能是一个综合体,不是一个框架就能说明的。
当使用消息队列作为进程间通信方式时,需要调整此内核参数
kernel.msgmnb = 4203520,消息队列的最大字节数
kernel.msgmni = 64,最多允许创建多少个消息队列
kernel.msgmax = 8192,消息队列单条数据最大的长度
————————————————————————————
ulimit设置
ulimit -n 要调整为100000甚至更大。 命令行下执行 ulimit -n 100000即可修改。如果不能修改,需要设置 /etc/security/limits.conf,加入
* soft nofile 262140
* hard nofile 262140
root soft nofile 262140
root hard nofile 262140
* soft core unlimited
* hard core unlimited
root soft core unlimited
root hard core unlimited
内核设置
net.unix.max_dgram_qlen = 100
swoole使用unix socket dgram来做进程间通信,如果请求量很大,需要调整此参数。系统默认为10,可以设置为100或者更大。
或者增加worker进程的数量,减少单个worker进程分配的请求量。
net.core.wmem_max
修改此参数增加socket缓存区的内存大小
net.ipv4.tcp_mem = 379008 505344 758016
net.ipv4.tcp_wmem = 4096 16384 4194304
net.ipv4.tcp_rmem = 4096 87380 4194304
net.core.wmem_default = 8388608
net.core.rmem_default = 8388608
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_tw_reuse
是否socket reuse,此函数的作用是Server重启时可以快速重新使用监听的端口。如果没有设置此参数,会导致server重启时发生端口未及时释放而启动失败
net.ipv4.tcp_tw_recycle
使用socket快速回收,短连接Server需要开启此参数
消息队列设置
当使用消息队列作为进程间通信方式时,需要调整此内核参数
kernel.msgmnb = 4203520,消息队列的最大字节数
kernel.msgmni = 64,最多允许创建多少个消息队列
kernel.msgmax = 8192,消息队列单条数据最大的长度
开启CoreDump
设置内核参数
kernel.core_pattern = /data/core_files/core-%e-%p-%t
通过ulimit -c命令查看当前coredump文件的限制
ulimit -c
如果为0,需要修改/etc/security/limits.conf,进行limit设置。
开启core-dump后,一旦程序发生异常,会将进程导出到文件。对于调查程序问题有很大的帮助
其他重要配置
net.ipv4.tcp_syncookies=1
net.ipv4.tcp_max_syn_backlog=81920
net.ipv4.tcp_synack_retries=3
net.ipv4.tcp_syn_retries=3
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_time = 300
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.ip_local_port_range = 20000 65000
net.ipv4.tcp_max_tw_buckets = 200000
net.ipv4.route.max_size = 5242880
查看配置是否生效
如:修改net.unix.max_dgram_qlen = 100后,通过
cat /proc/sys/net/unix/max_dgram_qlen
如果修改成功,这里是新设置的值。
摘自:http://wiki.swoole.com/wiki/page/11.html
本地socket--SOCK_DGRAM方式:http://blog.csdn.net/shanzhizi/article/details/16883601
当使用消息队列作为进程间通信方式时,需要调整此内核参数
kernel.msgmnb = 4203520,消息队列的最大字节数
kernel.msgmni = 64,最多允许创建多少个消息队列
kernel.msgmax = 8192,消息队列单条数据最大的长度
————————————————————————————
ulimit设置
ulimit -n 要调整为100000甚至更大。 命令行下执行 ulimit -n 100000即可修改。如果不能修改,需要设置 /etc/security/limits.conf,加入
* soft nofile 262140
* hard nofile 262140
root soft nofile 262140
root hard nofile 262140
* soft core unlimited
* hard core unlimited
root soft core unlimited
root hard core unlimited
内核设置
net.unix.max_dgram_qlen = 100
swoole使用unix socket dgram来做进程间通信,如果请求量很大,需要调整此参数。系统默认为10,可以设置为100或者更大。
或者增加worker进程的数量,减少单个worker进程分配的请求量。
net.core.wmem_max
修改此参数增加socket缓存区的内存大小
net.ipv4.tcp_mem = 379008 505344 758016
net.ipv4.tcp_wmem = 4096 16384 4194304
net.ipv4.tcp_rmem = 4096 87380 4194304
net.core.wmem_default = 8388608
net.core.rmem_default = 8388608
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_tw_reuse
是否socket reuse,此函数的作用是Server重启时可以快速重新使用监听的端口。如果没有设置此参数,会导致server重启时发生端口未及时释放而启动失败
net.ipv4.tcp_tw_recycle
使用socket快速回收,短连接Server需要开启此参数
消息队列设置
当使用消息队列作为进程间通信方式时,需要调整此内核参数
kernel.msgmnb = 4203520,消息队列的最大字节数
kernel.msgmni = 64,最多允许创建多少个消息队列
kernel.msgmax = 8192,消息队列单条数据最大的长度
开启CoreDump
设置内核参数
kernel.core_pattern = /data/core_files/core-%e-%p-%t
通过ulimit -c命令查看当前coredump文件的限制
ulimit -c
如果为0,需要修改/etc/security/limits.conf,进行limit设置。
开启core-dump后,一旦程序发生异常,会将进程导出到文件。对于调查程序问题有很大的帮助
其他重要配置
net.ipv4.tcp_syncookies=1
net.ipv4.tcp_max_syn_backlog=81920
net.ipv4.tcp_synack_retries=3
net.ipv4.tcp_syn_retries=3
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_time = 300
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.ip_local_port_range = 20000 65000
net.ipv4.tcp_max_tw_buckets = 200000
net.ipv4.route.max_size = 5242880
查看配置是否生效
如:修改net.unix.max_dgram_qlen = 100后,通过
cat /proc/sys/net/unix/max_dgram_qlen
如果修改成功,这里是新设置的值。
摘自:http://wiki.swoole.com/wiki/page/11.html
本地socket--SOCK_DGRAM方式:http://blog.csdn.net/shanzhizi/article/details/16883601