renzhelife-www.internet-dz.com http://www.baidu.comhttp://www.internet-dz.com zh-CN Copyright 2003-2018, ITeye.com http://www.internet-dz.com/amyh5163sjb/tech/rss ITeye - 做最棒的软件开发交流社区 简单的service编写 nginx php-fpm-www.internet-dz.com nginx


几个方法

start 直接启动 查看返回值是否是0 如果0则success 非0 则failure

stop 直接调用killproc

reload 调用nginx -s reload

restart stop,start

test 调用nginx -t

status 直接调用status


几个方法killproc, status, success, failure 来自/etc/init.d/functions 详细方法:/etc/init.d/functions说明




php-fpm

start , stop ,restart|reload, status




todo:等有时间写个基于pid 和 conf的... 这样就能支持多php-fpm 了,这玩意儿先凑合用着




已有 8 人发表留言,猛击->>这里<<-参与讨论


ITeye推荐



]]>
Wed, 16 Nov 2011 03:41:00 +0800 http://www.baidu.comhttp://www.internet-dz.com/blog/1261063 http://www.internet-dz.com/blog/1261063
/etc/init.d/functions 说明-www.internet-dz.com from:http://www.internet-dz.com/amyh5163sjb/adcxf/article/details/4013579

functions这个脚本是给/etc/init.d里边的文件使用的。提供了一些基础的功能,看看里边究竟有些什么。首先会设置umask,path,还有语言环境,然后会设置success,failure,warning,normal几种情况下的字体颜色。下面再看看提供的重要方法:
checkpid:检查是否已存在pid,如果有一个存在,返回0(通过查看/proc目录)
daemon:启动某个服务。/etc/init.d目录部分脚本的start使用到这个
killproc:杀死某个进程。/etc/init.d目录部分脚本的stop使用到这个
pidfileofproc:寻找某个进程的pid
pidofproc:类似上面的,只是还查找了pidof命令
status:返回一个服务的状态
echo_success,echo_failure,echo_passed,echo_warning分别输出各类信息
success,failure,passed,warning分别记录日志并调用相应的方法
action:打印某个信息并执行给定的命令,它会根据命令执行的结果来调用 success,failure方法
strstr:判断$1是否含有$2
confirm:显示 "Start service $1 (Y)es/(N)o/(C)ontinue? [Y]"的提示信息,并返回选择结果

详细分析:

# -*-Shell-script-*-
#
# functionsThis file contains functions to be used by most or all# 注释 :该脚本几乎被 /etc/init.d/ 下的所有脚本所调用,因为它包含了大量的
#shell scripts in the /etc/init.d directory.# 的基础函数。同时也被 /etc/rc.d/rc.sysinit ,例如 success、action、failure 等函数
#

TEXTDOMAIN=initscripts# 设置 TEXTDOMAIN 变量
##########################################################################################################################################################
# Make sure umask is sane# 确保 root 用户的 umask 是正确的 022 (也就是 rwxr-xr-x)
umask 022
# Set up a default search path.# 设置默认的 PATH 变量
PATH="/sbin:/usr/sbin:/bin:/usr/bin:/usr/X11R6/bin"# 默认为 /sbin:/usr/sbin:/bin:/usr/bin:/usr/X11R6/bin
export PATH# 导出为环境变量
# Get a sane screen width# 设置正确的屏幕宽度
[ -z "${COLUMNS:-}" ] && COLUMNS=80# 如果 COLUMNS 变量的值为空,则设置为 80 (列)
[ -z "${CONSOLETYPE:-}" ] && CONSOLETYPE="`/sbin/consoletype`"# 如果 CONSOLETYPE 为空则设置 CONSOLETYPE 为 /sbin/consoletype 命令返回的值
# 一般是 vt 或者 pty 、serial
##########################################################################################################################################################
if [ -f /etc/sysconfig/i18n -a -z "${NOLOCALE:-}" ] ; then# 如果存在 /etc/sysconfig/i18n 且NOLOCALE变量的值为空,则
. /etc/sysconfig/i18n# 执行 /etc/sysconfig/i18n 文件,取得 LANG 变量的值
if [ "$CONSOLETYPE" != "pty" ]; then# 如果当前 console 类型不是 pty(远程登录),而是 vt 或者 serial ,则
case "${LANG:-}" in# 根据 LANG 的值作出选择
ja_JP*|ko_KR*|zh_CN*|zh_TW*|bn_*|bd_*|pa_*|hi_*|ta_*|gu_*)# 如果 LANG 是日文、中文简体、中文繁体、韩文等,则
export LC_MESSAGES=en_US#把 LC_MESSAGES 设置为 en_US
export LANG# 同时导出为环境变量
;;
*)
export LANG# 如果是其他类型的语言,则直接导出 LANG
;;
esac
else# 如果当前 consle 是 pty
[ -n "$LC_MESSAGES" ] && export LC_MESSAGES# 且如果 LC_MESSAGES 不为空,则直接导出 LC_MESSAGES
export LANG
fi
fi
##########################################################################################################################################################
# 下面是设置 success、failure、passed、warning 4种情况下的字体颜色的
# Read in our configuration
if [ -z "${BOOTUP:-}" ]; then# 首先如果 BOOTUP变量为空,则
if [ -f /etc/sysconfig/init ]; then# 如果存在 /etc/sysconfig/init 文件,执行 /etc/sysconfig/init 文件
. /etc/sysconfig/init
else# 否则我们就手工设置
# This all seem confusing? Look in /etc/sysconfig/init,
# or in /usr/doc/initscripts-*/sysconfig.txt
BOOTUP=color#第一设置 BOOTUP 变量,默认就是 color
RES_COL=60# 第二设置设置在屏幕的第几列输出后面的 "[ xxx ]" ,默认是第60列
MOVE_TO_COL="echo -en//033[${RES_COL}G"# MOVE_TO_COL 是用于打印 "OK" 或者 "FAILED" ,或者 "PASSED" ,或者"WARNING"之前的部分,不含 "["
SETCOLOR_SUCCESS="echo -en//033[1;32m"#SETCOLOR_SUCCESS设置后面的字体都为绿色
SETCOLOR_FAILURE="echo -en//033[1;31m"# SETCOLOR_FAILURE 设置后面将要输出的字体都为红色
SETCOLOR_WARNING="echo -en//033[1;33m"# SETCOLOR_WARNING 设置后面将要输出的字体都为黄色
SETCOLOR_NORMAL="echo -en//033[0;39m"#SETCOLOR_NORMAL 设置后面输出的字体都为白色(默认)
LOGLEVEL=1
fi
if [ "$CONSOLETYPE" = "serial" ]; then# 如果是通过串口登录的,则全部取消彩色输出
BOOTUP=serial
MOVE_TO_COL=
SETCOLOR_SUCCESS=
SETCOLOR_FAILURE=
SETCOLOR_WARNING=
SETCOLOR_NORMAL=
fi
fi
##########################################################################################################################################################
if [ "${BOOTUP:-}" != "verbose" ]; then# 如果 BOOTUP 变量的值不为 verbose ,则
INITLOG_ARGS="-q"# 把 INITLOG_ARGS 的值设置为 -q (安静模式)
else# 否则
INITLOG_ARGS=# 把 INITLOG_ARGS 的值请空
fi
##########################################################################################################################################################
# Check if $pid (could be plural) are running# 下面定义一个函数 checkpid (),目的是检查 /proc 下是否存在指定的目录(例如 /proc/1/)
checkpid() {# 如果有任意一个存在,则返回0;
local i
for i in $* ; do
[ -d "/proc/$i" ] && return 0
done
return 1# 如果给出的参数全部不存在对应的目录,则返回1
}
##########################################################################################################################################################
# A function to start a program.# 下面定义最重要的一个函数,daemon 函数,它的作用是启动某项服务。/etc/init.d/ 下的脚本的 start 部分都会用到它
daemon() {
# Test syntax.
local gotbase= force=
local base= user= nice= bg= pid=
nicelevel=0
while [ "$1" != "${1##[-+]}" ]; do# daemon函数本身可以指定多个选项,例如--check<value> ,--check=<value> ,
case $1 in
'') echo $"$0: Usage: daemon [+/-nicelevel] {program}"# 也可以指定 nice 值
return 1;;
--check)
base=$2
gotbase="yes"
shift 2
;;
--check=?*)
base=${1#--check=}
gotbase="yes"
shift
;;
--user)# 也可以指定要以什么用户身份运行(--user <usr> , --user=<usr>)
user=$2
shift 2
;;
--user=?*)
user=${1#--user=}
shift
;;
--force)
force="force"#--force 表示强制运行
shift
;;
[-+][0-9]*)
nice="nice -n $1"# 如果 daemon 的第一个参数是数字,则认为是 nice 值
shift
;;
*) echo $"$0: Usage: daemon [+/-nicelevel] {program}"
return 1;;
esac
done
# Save basename.#basename 就是从服务器的二进制程序的 full path 中取出最后的部分
[ -z "$gotbase" ] && base=${1##*/}
# See if it's already running. Look *only* at the pid file.# 检查该服务是否已经在运行。不过 daemon 函数只查看 pid 文件而已
if [ -f /var/run/${base}.pid ]; then# 如果 /var/run 下存在该服务的 pid 文件,则
local line p
read line < /var/run/${base}.pid# 从该 pid 文件每次读取一行,送给变量 line 。注意 pid 文件可能有多行,且不一定都是数字
for p in $line ; do#对于 line 变量的每个 word进行检查
[ -z "${p//[0-9]/}" -a -d "/proc/$p" ] && pid="$pid $p"# 如果 p 全部是数字,且存在 /proc/$p/ 目录,则认为该数字是一个 pid ,把它加入到 pid 变量
done# 到最后 pid 变量的值可能是有多个由空格分隔的数字组成
fi

[ -n "${pid:-}" -a -z "${force:-}" ] && return# 如果 pid 变量最终为空,则 force 变量为空(不强制启动),则返回
# make sure it doesn't core dump anywhere unless requested# 下面对该服务使用的资源作一些设置
ulimit -S -c ${DAEMON_COREFILE_LIMIT:-0} >/dev/null 2>&1# ulimit 是控制由该 shell 启动的进程能够使用的资源,-S 是 soft control 的意思,-c 是指最大的 core
#dump 文件大小,如果 DEAMON_COREFILE_LIMIT为空,则默认为 0

# if they set NICELEVEL in /etc/sysconfig/foo, honor it# 如果存在 /etc/sysconfi/foo 文件,且其中有 NICELEVEL 变量则用它代替daemon后面的那个 nice 值
[ -n "$NICELEVEL" ] && nice="nice -n $NICELEVEL"# 注意,这里的 nice 赋值是用 nice -n <value> 的格式,因为 nice本身可以启动命令,用这个格式较方便

# Echo daemon# 如果 BOOTUP 的值为 verbose ,则打印一个服务名
[ "${BOOTUP:-}" = "verbose" -a -z "$LSB" ] && echo -n " $base"
# And start it up.# 下面是开始启动它了
if [ -z "$user" ]; then# 如果 user 变量为空,则默认使用 root 启动它
$nice initlog $INITLOG_ARGS -c "$*"# 执行 nice -n <nice_value> initlog -q -c "$*"
else# 如果指定了用户,则
$nice initlog $INITLOG_ARGS -c "runuser -s /bin/bash - $user -c /"$*/""# 执行 nice -n <nice_value> initlog -q -c "runuser -s /bin/bash - <user> -c "$*"
fi
[ "$?" -eq 0 ] && success $"$base startup" || failure $"$base startup"# 如果上面的命令成功,则显示一个绿色的 [ OK ] ,否则显示 [ FAILURE ]
}
##########################################################################################################################################################
# A function to stop a program.# 下面定义另外一个很重要的函数 killproc ,/etc/init.d/ 下面的脚本的 stop 部分都会用到它
killproc() {
RC=0# RC 是最终返回的值,初始化为 0
# Test syntax.
if [ "$#" -eq 0 ]; then# killproc 函数的语法格式是 killproc <service> [<signal>] ,例如 killproc sm-client 9
echo $"Usage: killproc {program} [signal]"
return 1
fi
notset=0# noset 是用于检查用户是否指定了 kill 要使用的信号
# check for second arg to be kill level
if [ -n "$2" ]; then# 如果 $2 不为空,则表示用户有设定信号,则
killlevel=$2# 把 $2的值赋予 killlevel 变量
else# 否则
notset=1# notset 变量的值为1,同时 killlevel 为 '-9'(KILL 信号)
killlevel="-9"
fi
# 补充 :注意,并不是说用户没有指定信号地停止某项服务时,就会立即用 kill -9 这样的方式强制杀死,而是先用 TERM 信号,然后再用 KILL
# Save basename.
base=${1##*/}# basename 就是得出服务的名称
# Find pid.
pid=#把 pid 变量的值清空。注意,不是指 pid 变量的值等于下面脚本的执行结果,要看清楚
if [ -f /var/run/${base}.pid ]; then# 下面和上面的 daemon 函数一样找出 pid
local line p
read line < /var/run/${base}.pid
for p in $line ; do
[ -z "${p//[0-9]/}" -a -d "/proc/$p" ] && pid="$pid $p"
done
fi
if [ -z "$pid" ]; then# 不过和 daemon 不同的是,一旦 pid为空不会直接 return而是尝试用 pid命令再次查找
pid=`pidof -o $$ -o $PPID -o %PPID -x $1 || /# -o 是用于忽略某个 pid ,-o $$ 是忽略当前 shell 的 pid、-o $PPID 是忽略 shell 的 pid
pidof -o $$ -o $PPID -o %PPID -x $base`# -o%PPID 是忽略 pidof 命令的父进程,要查询的进程是 $1 (fullpath) 或者 $base
fi
# Kill it.
if [ -n "${pid:-}" ] ; then# 如果 pid 的值最终不为空,则
[ "$BOOTUP" = "verbose" -a -z "$LSB" ] && echo -n "$base "# 且 BOOTUP 的值为 verbose ,且 LSB 变量不为空,则打印一个服务名
if [ "$notset" -eq "1" ] ; then# 如果 notset 变量不为1,表示用户没有指定信号,则
if checkpid $pid 2>&1; then#调用 checkpid $pid 检查是否在 /proc/ 下存在进程目录,如果有
# TERM first, then KILL if not dead# 先尝试用 TERM 信息,不行再用 KILL 信号
kill -TERM $pid >/dev/null 2>&1# 执行 kill -TERM $pid
usleep 100000 # usleep 和 sleep 一样,不过单位是百万分之1秒。这里休眠1秒
if checkpid $pid && sleep 1 &&# 如果 checkpid $pid还是查到有 /proc/<pid>/ 目录存在,则表示还没有杀死,继续等待1秒
checkpid $pid && sleep 3 &&# 如果1秒后用 checkpid 检查还是有,则再等待3秒;
checkpid $pid ; then# 如果还是没有杀死,则用KILL 信号
kill -KILL $pid >/dev/null 2>&1#执行 kill -KILL 杀死它
usleep 100000# 等待1秒种
fi
fi
checkpid $pid#再次检查 pid 目录
RC=$?# 并把结果返回给 RC ,这就算是 killproc 的最后状态了
[ "$RC" -eq 0 ] && failure $"$base shutdown" || success $"$base shutdown"# 如果 RC 的值为0,则表示kill -9 没有杀死了进程,则调用 failure 函数,否则调用 success
RC=$((! $RC))
# use specified level only# 上面都是在没有指定信号的情况的,下面是用户指定了信号的。例如 restart)或者 reload)部
else# 这个 else 是针对 if [ "$notset" -eq "1" ] 的
if checkpid $pid; then# 如果检查到进程存在,则
kill $killlevel $pid >/dev/null 2>&1# 执行kill命令,但使用指定的信号 $killlevel
RC=$?# 并把状态值返回给变量 RC
[ "$RC" -eq 0 ] && success $"$base $killlevel" || failure $"$base $killlevel"# 如果 RC 为0则表示成功,调用 success;否则调用 failure 函数
fi
fi
else# 这个 else 是针对 if [ -n "${pid:-}" ] 的,也就是说没有pid 文件,pidof 命令也没有找到pid ,则
failure $"$base shutdown"# 调用 failure 函数,表示停止服务失败
RC=1# 同时RC 的值为1
fi
# Remove pid file if any.# 根据具体情况可能需要删除 pid 文件
if [ "$notset" = "1" ]; then# 如果 notset 不为1 ,也就是用户没有指定信号的情况
rm -f /var/run/$base.pid# 自动删除 /var/run 下的 pid 文件
fi
return $RC# 并把 RC 作为 exit status 返回
}
# 补充 :自所以删除 pid 文件只针对 notset 为1 的情况,是因为 -HUP 信号(重读配置),并不杀死进程,所以不能删除它的 pid 文件
# 例如下面 :
[root@mail init.d]# ps -ef |grep xinetd
root 2635 1 0 12:25 ? 00:00:00 xinetd -stayalive -pidfile /var/run/xinetd.pid
[root@mail init.d]# ./xinetd reload
Reloading configuration: [ OK ]
[root@mail init.d]# ps -ef |grep xinetd
root 2635 1 0 12:25 ? 00:00:00 xinetd -stayalive -pidfile /var/run/xinetd.pid
root 3927 3412 0 16:43 pts/0 00:00:00 grep xinetd
[root@mail init.d]#
可以看到 pid 在 reload 后并没有变
##########################################################################################################################################################
# A function to find the pid of a program. Looks *only* at the pidfile# 下面的 pidfileofproc 函数和 checkpid 类似,但不执行 pidof 命令,只查询 pid 文件
pidfileofproc() {
local base=${1##*/}

# Test syntax.
if [ "$#" = 0 ] ; then
echo $"Usage: pidfileofproc {program}"
return 1
fi
# First try "/var/run/*.pid" files
if [ -f /var/run/$base.pid ] ; then
local line p pid=
read line < /var/run/$base.pid
for p in $line ; do
[ -z "${p//[0-9]/}" -a -d /proc/$p ] && pid="$pid $p"
done
if [ -n "$pid" ]; then
echo $pid
return 0
fi
fi
}
##########################################################################################################################################################
# A function to find the pid of a program.# 下面的 pidofproc 函数和上面的 pidfileofproc 函数类似,但多了一步 pidof 命令
pidofproc() {
base=${1##*/}
# Test syntax.
if [ "$#" = 0 ]; then
echo $"Usage: pidofproc {program}"
return 1
fi
# First try "/var/run/*.pid" files
if [ -f /var/run/$base.pid ]; then
local line p pid=
read line < /var/run/$base.pid
for p in $line ; do
[ -z "${p//[0-9]/}" -a -d /proc/$p ] && pid="$pid $p"
done
if [ -n "$pid" ]; then
echo $pid
return 0
fi
fi
pidof -o $$ -o $PPID -o %PPID -x $1 || /
pidof -o $$ -o $PPID -o %PPID -x $base
}
##########################################################################################################################################################
status() {# 注释 :下面的 status 函数是判断服务的状态,总共有4种
local base=${1##*/}
local pid
# Test syntax.
if [ "$#" = 0 ] ; then
echo $"Usage: status {program}"
return 1
fi
# First try "pidof"# 同样是查找 pid 先。直接使用 pidof 命令
pid=`pidof -o $$ -o $PPID -o %PPID -x $1 || /
pidof -o $$ -o $PPID -o %PPID -x ${base}`
if [ -n "$pid" ]; then# 如果 pid 变量的值不为空,则表示找到进程,
echo $"${base} (pid $pid) is running..."# 则打印 "xxx (pid nnn) is running " ,
return 0#并返回 0
fi
# Next try "/var/run/*.pid" files#如果 pidof 命令没有找到,则尝试从 pid 文件找
if [ -f /var/run/${base}.pid ] ; then
read pid < /var/run/${base}.pid
if [ -n "$pid" ]; then#如果 pidof 命令找不到,但从 pid 文件找到了 pid ,则
echo $"${base} dead but pid file exists"# 打印 "xxx dead but pid file exists",
return 1# 并返回 1
fi
fi
# See if /var/lock/subsys/${base} exists# 如果 pidof 命令和 pid 文件都没有找到 pid ,则
if [ -f /var/lock/subsys/${base} ]; then# 如果在 /var/lock/subsys 下存在对应的文件,则
echo $"${base} dead but subsys locked"# 打印 “xxxx dead but subsys locked”,
return 2# 并返回 2
fi
echo $"${base} is stopped"# 如果 pidof命令、pidf 文件都没有找到pid ,且没有别锁,则打印 “xxx is stopped
return 3# 并返回3
}
##########################################################################################################################################################
# 注释 :下面的 echo_xxx 函数就是真正在屏幕上打印 [ ok ] 、[ PASSED ]、[ FAILURE ]、[ WARNING ] 的部分了
echo_success() {#下面是 echo_success 部分
[ "$BOOTUP" = "color" ] && $MOVE_TO_COL# 首先是打印 “[” 之前的空格
echo -n "[ "# 然后打印 "["
[ "$BOOTUP" = "color" ] && $SETCOLOR_SUCCESS# 设置字体为红色
echo -n $"OK"# 打印 OK
[ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL# 返回字体为白色
echo -n " ]"# 打印 "]"
echo -ne "/r"#换行。
return 0# 返回 0,其他一律返回 1
echo_failure() {
[ "$BOOTUP" = "color" ] && $MOVE_TO_COL
echo -n "["
[ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE
echo -n $"FAILED"
[ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
echo -n "]"
echo -ne "/r"
return 1
}
echo_passed() {
[ "$BOOTUP" = "color" ] && $MOVE_TO_COL
echo -n "["
[ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING
echo -n $"PASSED"
[ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
echo -n "]"
echo -ne "/r"
return 1
}
echo_warning() {
[ "$BOOTUP" = "color" ] && $MOVE_TO_COL
echo -n "["
[ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING
echo -n $"WARNING"
[ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
echo -n "]"
echo -ne "/r"
return 1
}
##########################################################################################################################################################
# Inform the graphical boot of our current state
update_boot_stage() {
if [ "$GRAPHICAL" = "yes" -a -x /usr/bin/rhgb-client ]; then
/usr/bin/rhgb-client --update="$1"
fi
return 0
}
##########################################################################################################################################################
# Log that something succeeded
success() {# success 函数除了打印 [ xxx ] 之外,还会使用 initlog 记录信息
if [ -z "${IN_INITLOG:-}" ]; then
initlog $INITLOG_ARGS -n $0 -s "$1" -e 1# -n 是 --name 的意思,-s 是 --string,-e 是 --event ,1 表示完全成功
else
# silly hack to avoid EPIPE killing rc.sysinit
trap "" SIGPIPE
echo "$INITLOG_ARGS -n $0 -s /"$1/" -e 1" >&21
trap - SIGPIPE
fi
[ "$BOOTUP" != "verbose" -a -z "$LSB" ] && echo_success
return 0
}
# Log that something failed
failure() {
rc=$?
if [ -z "${IN_INITLOG:-}" ]; then
initlog $INITLOG_ARGS -n $0 -s "$1" -e 2#failure 的话 --event 是 2是失败
else
trap "" SIGPIPE
echo "$INITLOG_ARGS -n $0 -s /"$1/" -e 2" >&21
trap - SIGPIPE
fi
[ "$BOOTUP" != "verbose" -a -z "$LSB" ] && echo_failure
[ -x /usr/bin/rhgb-client ] && /usr/bin/rhgb-client --details=yes
return $rc
}
# Log that something passed, but may have had errors. Useful for fsck
passed() {
rc=$?
if [ -z "${IN_INITLOG:-}" ]; then
initlog $INITLOG_ARGS -n $0 -s "$1" -e 1# passed 的话 --event 还是1
else
trap "" SIGPIPE
echo "$INITLOG_ARGS -n $0 -s /"$1/" -e 1" >&21
trap - SIGPIPE
fi
[ "$BOOTUP" != "verbose" -a -z "$LSB" ] && echo_passed
return $rc
}
# Log a warning
warning() {
rc=$?
if [ -z "${IN_INITLOG:-}" ]; then
initlog $INITLOG_ARGS -n $0 -s "$1" -e 1#warning 的话 --event 也是 1
else
trap "" SIGPIPE
echo "$INITLOG_ARGS -n $0 -s /"$1/" -e 1" >&21
trap - SIGPIPE
fi
[ "$BOOTUP" != "verbose" -a -z "$LSB" ] && echo_warning
return $rc
}
##########################################################################################################################################################
# Run some action. Log its output.# action 函数是另外一个最重要的函数,它的作用是打印某个提示信息并执行给定命令
tion() {
STRING=$1
echo -n "$STRING "
if [ "${RHGB_STARTED}" != "" -a -w /etc/rhgb/temp/rhgb-console ]; then
echo -n "$STRING " > /etc/rhgb/temp/rhgb-console
fi
shift
initlog $INITLOG_ARGS -c "$*" && success $"$STRING" || failure $"$STRING"
rc=$?
echo
if [ "${RHGB_STARTED}" != "" -a -w /etc/rhgb/temp/rhgb-console ]; then
if [ "$rc" = "0" ]; then
echo_success > /etc/rhgb/temp/rhgb-console
else
echo_failed > /etc/rhgb/temp/rhgb-console
[ -x /usr/bin/rhgb-client ] && /usr/bin/rhgb-client --details=yes
fi
echo
fi
return $rc
}
##########################################################################################################################################################
# returns OK if $1 contains $2# strstr 函数是判断 $1 字符串是否含有 $2 字符串,是则返回0,否则返回1
() {
[ "${1#*$2*}" = "$1" ] && return 1
return 0
}
##########################################################################################################################################################
# Confirm whether we really want to run this service# confirm 函数是用于交互式的启动服务
nfirm() {
[ -x /usr/bin/rhgb-client ] && /usr/bin/rhgb-client --details=yes
while : ; do
echo -n $"Start service $1 (Y)es/(N)o/(C)ontinue? [Y] "# 会打印一个提示信息
read answer
if strstr $"yY" "$answer" || [ "$answer" = "" ] ; then# 如果 answer 变量是 y 或者 Y 则
return 0# 返回 0(但未真正启动)
elif strstr $"cC" "$answer" ; then# 如果 answer 是 c或者 C ,则
rm -f/var/run/confirm# 删除 /var/run/confirm 文件
[ -x /usr/bin/rhgb-client ] && /usr/bin/rhgb-client --details=no
return 2# 返回2
elif strstr $"nN" "$answer" ; then# 如果 answer 是 n 或者 N,则
return 1# 直接返回1
fi
done
}



已有 0 人发表留言,猛击->>这里<<-参与讨论


ITeye推荐



]]>
Wed, 16 Nov 2011 02:24:00 +0800 http://www.baidu.comhttp://www.internet-dz.com/blog/1261064 http://www.internet-dz.com/blog/1261064
各种浏览器用户体验比较-www.internet-dz.com <wbr><wbr>哪个浏览器速度最快?哪种浏览器最安全?我最喜欢回答这类的话题了。对于浏览器,我用过很多,有<span style="font-family:Times New Roman">IE</span><span style="font-family:宋体">内核的浏览器,还是非</span><span style="font-family:Times New Roman">IE</span><span style="font-family:宋体">内核浏览器,我统统的用过。好的就留下来自己使用,不好就直接咔嚓掉,因为浏览器的种类实在太多了,没办法全都写出来,下面我主要比较一下几款主流浏览器,</span> 个人意见,仅供参考。</wbr></wbr>

<wbr><strong><span style="font-family:Times New Roman">IE</span><span style="font-family:宋体">内核浏览器</span></strong></wbr>

1、IE浏览器:它的优点就是支持的应用多,目前几乎所有的网站都支持IE浏览器,尤其是IE的6.0版本作为XP的标配,用户群最多。缺点就是漏洞多,针对IE的木马插件特别多,非常影响用户体验。

<wbr><wbr><wbr><wbr><wbr>2<span style="font-family:宋体">、搜狗浏览器:它的优点是浏览速度快。应该比</span><span style="font-family:Times New Roman">ie9</span><span style="font-family:宋体">略快一些。兼容性也不错,因为它是双核心的浏览器。缺点就是不方便,一下子换</span><span style="font-family:Times New Roman">IE</span><span style="font-family:宋体">核心,一下子换高速模式的,还有广告太多,而且安全性不高,容易假死,资源占用略高。</span></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr><wbr><wbr><wbr>3<span style="font-family:宋体">、</span><span style="font-family:Times New Roman">360</span><span style="font-family:宋体">安全浏览器:是不是真的安全,见仁见智吧。但是这款浏览器问题多多,兼容性太差,而且经常排斥其它的应用程序(呵呵,</span><span style="font-family:Times New Roman">360</span><span style="font-family:宋体">特色)。你看下百度知道里关于浏览器的求助,大多都是这款浏览器。浏览速度一般,资源占用较高。</span></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr><strong><wbr><wbr>非<span style="font-family:Times New Roman">IE</span><span style="font-family:宋体">内核浏览器</span><wbr></wbr></wbr></wbr></strong></wbr></wbr></wbr>

<wbr><wbr><wbr><wbr><wbr>4<span style="font-family:宋体">、火狐浏览器:在非</span><span style="font-family:Times New Roman">IE</span><span style="font-family:宋体">内核里面这款可以说很好用的一款浏览器,运行稳定,兼容性也不错,因为扩展程序非常的非富,所以功能相当的强大。但是现在版本一直在升级,用户反映大不如前了,目前国内的市场占有率也下滑到不足2%了。</span></wbr></wbr></wbr></wbr></wbr>

<wbr><span style="font-size:18px"><wbr><wbr><wbr>5<span style="font-family:宋体">、苹果<span style="font-family:Times New Roman">safari</span></span><span style="font-family:宋体">:这是个老牌的浏览器了,这么多年一直和</span><span style="font-family:Times New Roman">ie</span><span style="font-family:宋体">、火狐分庭抗争。速度上和谷歌以及</span><span style="font-family:Times New Roman"><span style="font-family:Times New Roman">opera</span></span><span style="font-family:宋体">并驾齐驱,难分伯仲。资源占用适中。但是遗憾的是存在对于网银和下载工具的兼容性问题,而且兼容性可能要比谷歌还要略差一些。而且我不太喜欢它的图标(呵呵,鸡蛋挑骨头)。<wbr></wbr></span></wbr></wbr></wbr></span></wbr>

6、谷歌Chrome浏览器:目前很火的浏览器,口碑相当好。也是我目前使用着的,喜欢他得功能就算简洁,速度绝对也是可以支持的,而且运行非常的稳定。插件扩展也非常丰富,其中最具识别度的就是其单独的浏览器窗口标签,用户很容易把不同的窗口拆分与合并,提高浏览效率。

总结一下吧,如果你习惯了IE内核,那就使用IE的最新版本IE 9.0,如果想赶一下时髦,体验一下国外最流行的浏览器,那推荐你使用谷歌Chrome吧,少了那些乱七八糟的按钮,速度也非常快!



已有 1 人发表留言,猛击->>这里<<-参与讨论


ITeye推荐



]]>
Tue, 15 Nov 2011 20:51:00 +0800 http://www.baidu.comhttp://www.internet-dz.com/blog/1261015 http://www.internet-dz.com/blog/1261015
为何产品升级后越来越烂?-www.internet-dz.com from:http://www.internet-dz.com/amyh5163sjb/2011/11/05/%E4%B8%BA%E4%BD%95%E4%BA%A7%E5%93%81%E5%8D%87%E7%BA%A7%E5%90%8E%E8%B6%8A%E6%9D%A5%E8%B6%8A%E7%83%82%EF%BC%9F/

最近体验了几个经常使用的产品的最新版本,包括:google reader、新浪微博、echofon等。发觉对大部分产品而言,新产品意味着比老版本的产品拥有更多无用的功能、更炫但更华而不实的界面、更复杂的操作体验、更差的性能、更多的bug等等。当然最近google reader新版本功能相对老版倒是更少,但改版后,依然受到了一堆人的痛骂。

为何一些原本简单易用的产品在经过几轮升级后,会变得如此垃圾呢?为何那么多的产品中,经过升级后能够越来越好的产品或服务极其缺少呢?

一个产品之所以能够称其为好产品首先决定于产品的愿景目标,其次是产品设计的核心设计理念,最后才是产品的设计和实现的方法。

在某个阶段做一个好产品相对容易,只需要产品提供的核心功能能够满足用户的需求就可以了,但要在一次一次的版本更新中,持续不断是做出与时俱进的好产品就很难,尤其是面临各种变化和诱惑:产品战略的变化、产品团队的变化、用户的变化、竞争态势的变化等等,以及在变化过程中的各种诱惑。这些变化和诱惑都可能导致产品升级过程中产品愿景目标、核心设计理念、细节设计的变化,最终导致产品升级的失败。

产品战略的变化:

公司整体产品战略的变化,可能导致某个产品在公司地位的变化,从而影响产品的战略、定位、策略等,而这种变化对某个产品的影响可能是致命性。以Google Reader为例,Google近期的社会化的战略重点是Google+,因此Google Reader、Gmail等所有的产品都必须围绕与Google+整合进行调整。这样导致在 Reader的改版中,对社会化分享进行了较大调整。为了产品间所谓的协同效应,毁掉了多少产品的美好未来。

产品团队的变化:

原有负责产品的人离职或不再负责,所谓“不破不立”,新人总有否定并推倒原有产品设计的冲动,这样方能体现自己工作的价值,而且新人对产品的愿景、设计理念大都有自己的一整套方法论,因此在做新一版本的产品设计时候会采用自己的方法论去重构产品,因此尽管只是老版本的升级版本,但产品团队、设计理念都早已变化。

与产品团队相关的还包括新人能力、对产品的感情、热情等方面的原因。

目标用户的变化:

随着用户数的快速增加,用户群也随之裂变,各类用户提出了貌似合理的形形色色需求。为了满足不同用户群的需求,产品不断新增功能,产品越来越臃肿。同时由于市场的成熟及竞争态势的变化,目标用户群的选择不再单一,用户对产品的期望值也有所变化。原有衡量优秀产品的标准可能也已变化,在此情况下,所有产品升级都面临如此的挑战:变还是不变,怎样变?怎样与时俱进?怎样均衡不同用户的需求和期望值?

竞争态势的变化:

由于竞争对手的杀入,尤其是竞争对手推出了颇具竞争力的类似产品,为了保持自己的竞争力,产品的重点不再是关注怎样更好满足用户的需求,不再是保持自己的节奏和独有风格继续发展,而是在关注竞争对手在做什么然后相互山寨,匆忙之下推出一个又一个与竞争对手大同小异的新版本,最终产品变成了没有生命力和灵魂的垃圾。

成功的副作用:

即便是同样的产品团队,在老版本大获成功后,新版本与老版本在品质上可能也是相去甚远。原因有很多,一个典型的情况是:在老版本时候,由于资源相对有限,不允许团队有太多想法,因此必须抵御住各种诱惑,专注于最重要的核心功能;另外由于团队成员都对成功有极度的饥饿感,大家还持有对产品的热情及共同目标。

成功后,资源不再是最大问题,因资源、时间、资金等因素压抑许久的各种“伟大思想”呼之欲出,顿觉所有的方向都是机会,都是为竞争对手筑起的竞争壁垒。专一、简洁成了保守者的代名词,平台化、多元化、一站式成了新的团队术语。

以前版本的大获成功,在我们这个成王败寇为唯一标准的国度,成功掩盖了团队所有的问题,公司资源无限倾斜,领导者的欲望也急剧膨胀,而团队目标不再单一,成功的欲望及热情不再象以前那样强烈。团队拥有和被赋予更多的期望、更多的资源、更多的承诺、更多的内耗、更多的混乱,最终果实是更烂的产品。此类现象我们可以称之为“成功的副作用”。

无答案的问答

怎样避免产品升级后越来越垃圾的陷阱呢,其实并没有什么标准答案。 以上问题其实很多时候并无绝对的对错之分,只是度的把控问题,同样的道理在不同的场景下讲对错就不一样。

因此最核心的问题实际上在于怎样在产品目标、团队能力、团队欲望、节奏之间要找到一个合适的平衡点,与时俱进,这样方能应对变化万千的世界。一个团队从一个成功走向另一个更大成功更需要对目标无比的专注、对团队能力清醒的认识、对欲望的有效把控以及合理的节奏感。





已有 0 人发表留言,猛击->>这里<<-参与讨论


ITeye推荐



]]>
Tue, 15 Nov 2011 15:04:00 +0800 http://www.baidu.comhttp://www.internet-dz.com/blog/1261065 http://www.internet-dz.com/blog/1261065
大数据排序或取重或去重相关问题-www.internet-dz.com

1. 给定a、b两个文件,各存放50亿个url,每个url各占64字节,内存限制是4G,让你找出a、b文件共同的url?
方案1:可以估计每个文件安的大小为50G×64=320G,远远大于内存限制的4G。所以不可能将其完全加载到内存中处理。考虑采取分而治之的方法。
s 遍历文件a,对每个url求取 ,然后根据所取得的值将url分别存储到1000个小文件(记为 )中。这样每个小文件的大约为300M。
s 遍历文件b,采取和a相同的方式将url分别存储到1000各小文件(记为 )。这样处理后,所有可能相同的url都在对应的小文件( )中,不对应的小文件不可能有相同的url。然后我们只要求出1000对小文件中相同的url即可。
s 求每对小文件中相同的url时,可以把其中一个小文件的url存储到hash_set中。然后遍历另一个小文件的每个url,看其是否在刚才构建的hash_set中,如果是,那么就是共同的url,存到文件里面就可以了。
方案2:如果允许有一定的错误率,可以使用Bloom filter,4G内存大概可以表示340亿bit。将其中一个文件中的url使用Bloom filter映射为这340亿bit,然后挨个读取另外一个文件的url,检查是否与Bloom filter,如果是,那么该url应该是共同的url(注意会有一定的错误率)。

2. 有10个文件,每个文件1G,每个文件的每一行存放的都是用户的query,每个文件的query都可能重复。要求你按照query的频度排序。
方案1:
s 顺序读取10个文件,按照hash(query)%10的结果将query写入到另外10个文件(记为 )中。这样新生成的文件每个的大小大约也1G(假设hash函数是随机的)。
s 找一台内存在2G左右的机器,依次对 用hash_map(query, query_count)来统计每个query出现的次数。利用快速/堆/归并排序按照出现次数进行排序。将排序好的query和对应的query_cout输出到文件中。这样得到了10个排好序的文件(记为 )。
s 对 这10个文件进行归并排序(内排序与外排序相结合)。
方案2:
一般query的总量是有限的,只是重复的次数比较多而已,可能对于所有的query,一次性就可以加入到内存了。这样,我们就可以采用trie树/hash_map等直接来统计每个query出现的次数,然后按出现次数做快速/堆/归并排序就可以了。
方案3:
与方案1类似,但在做完hash,分成多个文件后,可以交给多个文件来处理,采用分布式的架构来处理(比如MapReduce),最后再进行合并。

3. 有一个1G大小的一个文件,里面每一行是一个词,词的大小不超过16字节,内存限制大小是1M。返回频数最高的100个词。
方案1:顺序读文件中,对于每个词x,取 ,然后按照该值存到5000个小文件(记为 ) 中。这样每个文件大概是200k左右。如果其中的有的文件超过了1M大小,还可以按照类似的方法继续往下分,知道分解得到的小文件的大小都不超过1M。对 每个小文件,统计每个文件中出现的词以及相应的频率(可以采用trie树/hash_map等),并取出出现频率最大的100个词(可以用含100个结点 的最小堆),并把100词及相应的频率存入文件,这样又得到了5000个文件。下一步就是把这5000个文件进行归并(类似与归并排序)的过程了。

4. 海量日志数据,提取出某日访问百度次数最多的那个IP。
方案1:首先是这一天,并且是访问百度的日志中的IP取出来,逐个写入到一个大文件中。注意到IP是32位的,最多有 个 IP。同样可以采用映射的方法,比如模1000,把整个大文件映射为1000个小文件,再找出每个小文中出现频率最大的IP(可以采用hash_map进 行频率统计,然后再找出频率最大的几个)及相应的频率。然后再在这1000个最大的IP中,找出那个频率最大的IP,即为所求。

5. 在2.5亿个整数中找出不重复的整数,内存不足以容纳这2.5亿个整数。
方案1:采用2-Bitmap(每个数分配2bit,00表示不存在,01表示出现一次,10表示多次,11无意义)进行,共需内存 内存,还可以接受。然后扫描这2.5亿个整数,查看Bitmap中相对应位,如果是00变01,01变10,10保持不变。所描完事后,查看bitmap,把对应位是01的整数输出即可。
方案2:也可采用上题类似的方法,进行划分小文件的方法。然后在小文件中找出不重复的整数,并排序。然后再进行归并,注意去除重复的元素。

6. 海量数据分布在100台电脑中,想个办法高校统计出这批数据的TOP10。
方案1:
s 在每台电脑上求出TOP10,可以采用包含10个元素的堆完成(TOP10小,用最大堆,TOP10大,用最小堆)。比如求TOP10大,我们首先取前 10个元素调整成最小堆,如果发现,然后扫描后面的数据,并与堆顶元素比较,如果比堆顶元素大,那么用该元素替换堆顶,然后再调整为最小堆。最后堆中的元 素就是TOP10大。
s 求出每台电脑上的TOP10后,然后把这100台电脑上的TOP10组合起来,共1000个数据,再利用上面类似的方法求出TOP10就可以了。

7. 怎么在海量数据中找出重复次数最多的一个?
方案1:先做hash,然后求模映射为小文件,求出每个小文件中重复次数最多的一个,并记录重复次数。然后找出上一步求出的数据中重复次数最多的一个就是所求(具体参考前面的题)。

8. 上千万或上亿数据(有重复),统计其中出现次数最多的钱N个数据。
方案1:上千万或上亿的数据,现在的机器的内存应该能存下。所以考虑采用hash_map/搜索二叉树/红黑树等来进行统计次数。然后就是取出前N个出现次数最多的数据了,可以用第6题提到的堆机制完成。

9. 1000万字符串,其中有些是重复的,需要把重复的全部去掉,保留没有重复的字符串。请怎么设计和实现?
方案1:这题用trie树比较合适,hash_map也应该能行。

10. 一个文本文件,大约有一万行,每行一个词,要求统计出其中最频繁出现的前10个词,请给出思想,给出时间复杂度分析。
方案1:这题是考虑时间效率。用trie树统计每个词出现的次数,时间复杂度是O(n*le)(le表示单词的平准长度)。然后是找出出现最频繁的 前10个词,可以用堆来实现,前面的题中已经讲到了,时间复杂度是O(n*lg10)。所以总的时间复杂度,是O(n*le)与O(n*lg10)中较大 的哪一个。

11. 一个文本文件,找出前10个经常出现的词,但这次文件比较长,说是上亿行或十亿行,总之无法一次读入内存,问最优解。
方案1:首先根据用hash并求模,将文件分解为多个小文件,对于单个文件利用上题的方法求出每个文件件中10个最常出现的词。然后再进行归并处理,找出最终的10个最常出现的词。

12. 100w个数中找出最大的100个数。
方案1:在前面的题中,我们已经提到了,用一个含100个元素的最小堆完成。复杂度为O(100w*lg100)。
方案2:采用快速排序的思想,每次分割之后只考虑比轴大的一部分,知道比轴大的一部分在比100多的时候,采用传统排序算法排序,取前100个。复杂度为O(100w*100)。
方案3:采用局部淘汰法。选取前100个元素,并排序,记为序列L。然后一次扫描剩余的元素x,与排好序的100个元素中最小的元素比,如果比这个 最小的要大,那么把这个最小的元素删除,并把x利用插入排序的思想,插入到序列L中。依次循环,知道扫描了所有的元素。复杂度为O(100w*100)。

13. 寻找热门查询:
搜索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下来,每个查询串的长度为1-255字节。假设目前有一千万个记录,这些查询串的重复 读比较高,虽然总数是1千万,但是如果去除重复和,不超过3百万个。一个查询串的重复度越高,说明查询它的用户越多,也就越热门。请你统计最热门的10个 查询串,要求使用的内存不能超过1G。
(1) 请描述你解决这个问题的思路;
(2) 请给出主要的处理流程,算法,以及算法的复杂度。
方案1:采用trie树,关键字域存该查询串出现的次数,没有出现为0。最后用10个元素的最小推来对出现频率进行排序。

14. 一共有N个机器,每个机器上有N个数。每个机器最多存O(N)个数并对它们操作。如何找到 个数中的中数?
方案1:先大体估计一下这些数的范围,比如这里假设这些数都是32位无符号整数(共有 个)。我们把0到 的整数划分为N个范围段,每个段包含 个整数。比如,第一个段位0到 ,第二段为 到 ,…,第N个段为 到 。 然后,扫描每个机器上的N个数,把属于第一个区段的数放到第一个机器上,属于第二个区段的数放到第二个机器上,…,属于第N个区段的数放到第N个机器上。 注意这个过程每个机器上存储的数应该是O(N)的。下面我们依次统计每个机器上数的个数,一次累加,直到找到第k个机器,在该机器上累加的数大于或等于 ,而在第k-1个机器上的累加数小于 ,并把这个数记为x。那么我们要找的中位数在第k个机器中,排在第 位。然后我们对第k个机器的数排序,并找出第 个数,即为所求的中位数。复杂度是 的。
方案2:先对每台机器上的数进行排序。排好序后,我们采用归并排序的思想,将这N个机器上的数归并起来得到最终的排序。找到第n个便是所求。复杂度是n(i)的。

15. 最大间隙问题
给定n个实数 ,求着n个实数在实轴上向量2个数之间的最大差值,要求线性的时间算法。
方案1:最先想到的方法就是先对这n个数据进行排序,然后一遍扫描即可确定相邻的最大间隙。但该方法不能满足线性时间的要求。故采取如下方法:
s 找到n个数据中最大和最小数据max和min。
s 用n-2个点等分区间[min, max],即将[min, max]等分为n-1个区间(前闭后开区间),将这些区间看作桶,编号为 ,且桶 的上界和桶i+1的下届相同,即每个桶的大小相同。每个桶的大小为: 。实际上,这些桶的边界构成了一个等差数列(首项为min,公差为 ),且认为将min放入第一个桶,将max放入第n-1个桶。
s 将n个数放入n-1个桶中:将每个元素 分配到某个桶(编号为index),其中 ,并求出分到每个桶的最大最小数据。
s 最大间隙:除最大最小数据max和min以外的n-2个数据放入n-1个桶中,由抽屉原理可知至少有一个桶是空的,又因为每个桶的大小相同,所以最大间隙 不会在同一桶中出现,一定是某个桶的上界和气候某个桶的下界之间隙,且该量筒之间的桶(即便好在该连个便好之间的桶)一定是空桶。也就是说,最大间隙在桶 i的上界和桶j的下界之间产生 。一遍扫描即可完成。

16. 将多个集合合并成没有交集的集合:给定一个字符串的集合,格式如: 。要求将其中交集不为空的集合合并,要求合并完成的集合之间无交集,例如上例应输出 。
(1) 请描述你解决这个问题的思路;
(2) 给出主要的处理流程,算法,以及算法的复杂度;
(3) 请描述可能的改进。
方案1:采用并查集。首先所有的字符串都在单独的并查集中。然后依扫描每个集合,顺序合并将两个相邻元素合并。例如,对于 , 首先查看aaa和bbb是否在同一个并查集中,如果不在,那么把它们所在的并查集合并,然后再看bbb和ccc是否在同一个并查集中,如果不在,那么也把 它们所在的并查集合并。接下来再扫描其他的集合,当所有的集合都扫描完了,并查集代表的集合便是所求。复杂度应该是O(NlgN)的。改进的话,首先可以 记录每个节点的根结点,改进查询。合并的时候,可以把大的和小的进行合,这样也减少复杂度。

17. 最大子序列与最大子矩阵问题
数组的最大子序列问题:给定一个数组,其中元素有正,也有负,找出其中一个连续子序列,使和最大。
方案1:这个问题可以动态规划的思想解决。设 表示以第i个元素 结尾的最大子序列,那么显然 。基于这一点可以很快用代码实现。
最大子矩阵问题:给定一个矩阵(二维数组),其中数据有大有小,请找一个子矩阵,使得子矩阵的和最大,并输出这个和。
方案1:可以采用与最大子序列类似的思想来解决。如果我们确定了选择第i列和第j列之间的元素,那么在这个范围内,其实就是一个最大子序列问题。如何确定第i列和第j列可以词用暴搜的方法进行。

转自:http://www.internet-dz.com/amyh5163sjb/jiaxiaobosuper/blog/item/5715981c8c7f54d3a686694b.html




已有 2 人发表留言,猛击->>这里<<-参与讨论


ITeye推荐



]]>
Tue, 15 Nov 2011 11:27:00 +0800 http://www.baidu.comhttp://www.internet-dz.com/blog/1260934 http://www.internet-dz.com/blog/1260934
多用户openvpn的架设与配置-www.internet-dz.com from:http://www.internet-dz.com/amyh5163sjb/read.php?194


在线上系统紧急维护中,效率显得尤为重要,解决问题是当务之急,直接连接到线上服务器并进行维护。

一般来说,机房的机器是不能通过公网来直接连接的,很多的解决办法是通过vpn来解决,这里介绍的就是vpn的一种,openvpn,能快速搭建一个多Client单Server的VPN应用,适用Windows的客户端,Linux的服务器端。目的是能够快速连入机房环境,更有效的维护和管理服务系统。

首先从网上down一个openvpn的源码包,解压,编译。官方网站为 openvpn.net



$ cd /root
$ wget http://www.internet-dz.com/amyh5163sjb/download_action.php?openvpn-2.0.9.tar.gz
$ tar xfz openvpn-2.0.9.tar.gz
$ cd openvpn-2.0.9
$ ./configure --disable-lzo
$ make
$ make install


到此,安装完成,接下来就是配置
首先要生成一些key文件


$ cd easy-rsa
#看README,里面有详细的介绍
$ . vars #这里是配置当前shell环境的目录变量
$ ./build-ca #创建公钥
$ ./build-dh #创建连接加密字串
$ ./build-key-server server #创建服务端key,并取名server
$ ./build-key space #创建客户端key,并取名为space


创建以上文件时,没有默认值的信息需要手工填写,有默认值的可以忽略,其中的states,province,city,company,statement尽量填写一致,生成客户端key时,如需生成多个,common name请填写不一样的,不然重名将不能创建成功


完成后,可以看到 easy-rsa目录下多出一个keys目录,为了方便管理,我们在/etc/下创建一个openvpn目录,将keys目录下所有的文件均copy到其中


$ mkdir /etc/openvpn
$ cd keys
$ cp * /etc/openvpn


然后我们要进行服务端配置,在这里假设当前服务器的外网ip为: 202.103.66.22 内网ip为 192.168.102.11

解压后的目录中, /root/openvpn-2.0.9/sample-config-files/server.conf 为sample的服务端配置文件,里面都有详细的注释,以下为一个我的配置范例,可以参照修改


;local 202.103.66.22
port 1194
proto udp

# "dev tun" will create a routed IP tunnel,
# "dev tap" will create an ethernet tunnel.
;dev tap
dev tun

# SSL/TLS root certificate (ca), certificate
# (cert), and private key (key). Each client
# and the server must have their own cert and
# key file. The server and all clients will
# use the same ca file.
ca /etc/openvpn/ca.crt
cert /etc/openvpn/server.crt
key /etc/openvpn/server.key # This file should be kept secret

# Diffie hellman parameters.
dh /etc/openvpn/dh1024.pem

# Configure server mode and supply a VPN subnet
# for OpenVPN to draw client addresses from.
server 10.253.0.0 255.255.255.0

# Maintain a record of client <-> virtual IP address
ifconfig-pool-persist ipp.txt

# Uncomment this directive to allow different
# clients to be able to "see" each other.
;client-to-client

# Uncomment this directive if multiple clients
;duplicate-cn

# Enable compression on the VPN link.
;comp-lzo

# Other option
daemon
keepalive 10 120
;max-clients 100
;push "route 192.168.20.0 255.255.255.0"
;user nobody
;group nobody
;persist-key
;persist-tun
status /etc/openvpn/openvpn-status.log
log /etc/openvpn/openvpn.log
;log-append openvpn.log
verb 3
;mute 20


配置完成后,保存到/etc/openvpn/下,命名为openvpn.cfg

注意配置文件中的端口号(此处为port 1194)以及服务器ip配置(此处为 server 10.253.0.0 255.255.255.0 ),建议配置为不常见的端口号以及ip端,防止冲突。

接下来是启动openvpn服务


$ /usr/local/sbin/openvpn --config /etc/openvpn/openvpn.cfg



如服务启动正常,可以开始客户端的配置,将刚刚创建的文件中的 ca.crt space.key space.crt 这三个文件copy到你的客户端windows机器上,这里假设三个文件放到了C:\下。客户端安装官网的windows端软件,安装完成后创建一个虚拟连接,生成一个默认配置文件,修改其中配置,这里提供一个我的配置:



client
;dev tap
dev tun
;proto tcp
proto udp
remote 202.103.66.22 1194
resolv-retry infinite
nobind

# SSL/TLS parms.
ca C:\\ca.crt
cert C:\\space.crt
key C:\\space.key

# If a tls-auth key is used on the server
# then every client must also have the key.
;tls-auth ta.key 1

# Enable compression on the VPN link.
;comp-lzo

# Set log file verbosity.
verb 3

# Silence repeating messages
;mute 20




完成后保存为client.opvn,鼠标右键单击此文件,在菜单中点击 "Start OpenVPN on this config file"

好了,现在用Secure CRT 连接 10.253.0.1,输入root帐户密码,是不是能进入服务器了?

完工,呵呵



已有 1 人发表留言,猛击->>这里<<-参与讨论


ITeye推荐



]]>
Mon, 14 Nov 2011 10:47:00 +0800 http://www.baidu.comhttp://www.internet-dz.com/blog/1261066 http://www.internet-dz.com/blog/1261066
杂谈:Google要解决的关于Android的问题-www.internet-dz.com Android发展到今天已经到达了一个非常成功的地步,而且它还在越变越好。智能移动设备也出现了Apple,Microsoft和Google三分天下,当然现在Microsoft的份额还有点可怜,但我相信以Microsoft的实力,还是有能力争取三分天下的。对于苹果总是能给世人带来惊喜,让人们像追星一样的成为粉丝,着实有它的神奇之处。但是关于Android,虽然很成功,但是总是有让人感到不快的地方,批评声也总是不断。个人认为,这些不足和批评都应该由Google来负主要责任,下面就谈谈Google应该在Android上需要加强的地方。

1. Google要认真的做Android,把它做的精益求精

苹果的产品能够那样的被人追捧,其中一个很重要的原因就是它足够的好,有足够的吸引力,不但硬件配置强劲,外观精美,更重要的是它的软件能够处处为用户着想,有着优秀的用户体验。iOS为开发者想的也足够周到,相传iOS的开发工具很完善,文档很完备,我没有接触过不晓得是真是假。

但对于Android,情况不是很好,甚至可以用糟糕来形容。

Android系统本身很粗糙,系统本身的Bug比较多,这点各大厂商最清楚,搞过Android本身代码的人也清楚。很多人在说因为Android开源,所以里面难免有问题,我想这是借口,但不是理由,现在的开源软件那么多,还没有哪个做的有Android这么粗糙的。我想Google之所以没有尽责的去把Android做好的原因就是Google不是靠Android来赢利的,不是靠卖Android手机为生的,起码不是像Apple或Microsoft那样直接赢利。所以,它只管往里面添加新的东西,不需要做太好,反正它自己不出手机。其余的事情就全都丢给厂商了,反正是开源的,又是免费的,你拿去随便搞吧,这应该是Google的态度和想法。反过来对于厂商来讲,这就是开源的代价,虽然有着开源和免费的晃子,但别人可能给你的是个半成品。做过Android解决方案的人都知道,每次拿到Android源码都要先用一段时间去解源码的Bug,然后才去做定制和开发。

Android SDK做的也不不够好,文档不够完善,API不够稳定,也不好用,封装性和统一性都不够好。

所以,如果Google想让Android继续强大,必须端正态度,像做自己的产品一样把它做成精品。这样,一旦有一天Google想要把Android变成自家的产品,拿到的也还是精品。

2. Google不要浮躁,安心的把东西做好,自然会受到用户和开发者的肯定

表现在,今年10月初Apple发布了iPhone4S和iOS5,于是Google就也在10月发布了Android 4.0. 我想问的是,Android 4.0真的准备好了吗?以前的报道说4.0要到年底或明年初才能发布。所以,在十月发布Android 4.0就是为了跟Apple抢镜头,所以都离发布日快一个月了,厂商们还是没有拿到4.0的源码。用户和开发者更是没有盼头。

事实上,即使明天就把源码公布了,厂商也还需要时间去移植和定制,所以4.0的手机年底前能上市就不错了。

Apple就很本分,很安心的把自己的产品做到完美。iPad一年才升级一次,iPhone4S更是在iPhone出现一年半才发布,而Android的源码升级和SDK的升级却是平均每二个月一次,就算二家的研发团队水平是一样的,产品的质量也是有分晓的。

其实原因还是在于Google自己不卖手机,它只管开发新的东西,不用去管系统的质量。就好比一个人只管写代码,从不管测试和代码的质量一样,代码的好坏可想而知。如此的浮躁,一味的去赶超,没有意义,就像中国,总是在学习别人,总是想超越别人,却还是被人家远远的甩在后面。

Google应该好好的安心的搞Android,让它真正的成为一个受人追捧的优秀系统。

3. Google要做到对所有厂商公平

在收购Moto之前,Google就是这样,总是把SDK和Android源码优先公开给Samsung和Moto这样的巨头,一些小的厂商,特别是中国的厂商要在向全世界所有人公开时,才能拿到SDK和源码。这里的差距和造成影响可想而知。

现在Google又大出血把Moto Mobility买了,它现在可是有能力生产硬件了。会不会对自家人Moto有偏心和私心,我想大家都明明白白的。或许,Google像苹果一样自己做软件,自己生产,自己销售的日子也不远了。

像Google董事长史密特说的,如果Google将Android闭源,或是对其他厂商不公,那是自掘坟墓,我想他是对的。但是Google真正的想法他会对我们说吗?就好像Google在收购Moto之前又有多少人知道呢!所以厂商有自己的准备还是明智的,像Samsung就大力发展自家Bada系统。Google可是个撒谎大王,之前都信誓旦旦的说过不搞浏览器,不搞社交,但是现在它的Chrome和Google+在不断的蚕食市场份额。但从另外的角度来讲,如果一个东西有前景,有市场,有钱赚,Google的实力又那么强,它有什么理由不去搞呢?它又怎么管自己曾经许诺过什么呢?不去搞的,才是真正的傻瓜。

4. 务必解决Android的分化问题

分化问题是困扰开发者和解决方案商的最大问题。全球Android设备千差万别,硬件配置各有千秋,软件系统也是各有特色,厂商定制也是有深有浅,各自都做了相当的努力,以求超凡脱俗。另外,屏幕分辨率的不统一也是让开发者和解决方案商煞费苦心。硬件配置,系统定制和分辨率都是开发者的恶梦。

iOS的开发者就幸运多了,他们可以把所有的精力都放在应该做的事情上,可以专心的开发应用,应用所能运行的设备都是一模一样的。这也是为什么App Store能收集那么多优秀应用的原因 ,也是它能吸引开发者的原因。Google的Android Market上的应用虽然也不少,但一大部分都是从App Store上面移植过来的,还有一部分是模仿App Store上面的应用开发的,真正属于自己的应用,说实话,并不多。

据说Android 4.0可以解决分化问题,希望真的如此。

5. 务必解决好用户手机升级问题

不可否认Android手机的升级是真TMD的拉圾,很多设备都无法获得升级。

当然,正是开源性和开放性的好处,现在绝大多数Android用户的升级都是通过非官方的刷机方式进行的。因为有一些第三方的开发团队在制作向普通用户免费开放的Android的ROM。但这毕竟不是长久之计,因为自己刷机风险很大,很容易刷成砖。

Apple的用户就幸福多了,iOS5出来了,连3GS都能成功升级,其他设备也都可以轻松升级。但是Android的每个新版本出来,能升级的设备总是有限。

Android的升级主要取决于厂商,因为你买的是厂商的手机,用的是厂商定制的系统,所以如果厂商提供升级,你就可以升级,否则,你只能冒着变砖的风险通过非官方方式进行刷机。

比如现在4.0要出来了,能升级的设备却少的可怜。

厂商要支持升级是很困难的,也是需要很大勇气的。因为厂商手中有它自己定制的Android,每当Google Release出Android升级后,它需要把它们进行融合,还需要时间去把它稳定,而这是很耗费人力的财力的事情,所以厂商的主管们要决定支持某款设备的升级是需要很大勇气的。特别是像4.0这次升级,源码和API的变化相当的大,整合代码的难度可想而知,对于厂商和开发者来讲就是一场恶梦。所以厂商宁愿不升级,而是基于新的Android重新定制新的版本,推出新款的手机,从成本上讲这与升级差不多,但带来的利益却不一样。比如,Samsung,Moto和HTC在每次Android升级后,都会出新的产品,对其已推出的产品的支持却很少,甚至没有。

搞来搞去,受害的是用户。

Google应该做出努力,达到某一天,其发布新的Android时,用户也能随即获得升级。



已有 0 人发表留言,猛击->>这里<<-参与讨论


ITeye推荐



]]>
Sun, 13 Nov 2011 23:18:00 +0800 http://www.baidu.comhttp://www.internet-dz.com/blog/1260444 http://www.internet-dz.com/blog/1260444
Android实战技巧:组件间通信---Intent和IntentFilter-www.internet-dz.com Understanding Intent and IntentFilter--理解Intent和IntentFilter Intent(意图)在Android中是一个十分重要的组件,它是连接不同应用的桥梁和纽带,也是让组件级复用(Activity和 Service)成为可能的一个重要原因。Intent的使用分为二个方面一个是发出Intent,另一个则是接收Intent用官方的说法就是Intent Resolving。本主将对Intent和IntentFilter进行一些介绍。
Intent和IntentFilter是Android和一种消息通信机制,可以让系统的组件之间进行通信。信息的载体就是Intent,它可以是一个要完成的动作请求,也可以一般性的消息广播,它可以由任意一个组件发出。消息,也就是Intent,最终也是要被组件来进行处理和消化。消息由组件发出,通常在消息的里面也会有会标记有目标组件的相关信息,另外目标组件也需要告诉系统,哪些消息是它所感兴趣的,它需要设置一些过滤器,以过滤掉无关的消息。
其实这里就好比学校里的广播,广播有时会播放通知,但有时也会播放要执行的动作,比如打扫卫生。消息中通常都会说明消息的目标对象,可能是计算机学院,可能是老师,也可能是英语系的人才需要关注。而每个人,或是学院组织,也只关心与他们有关的消息,当然这里就要他们自己去判断哪些是与他们有关的消息了。在Android当中消息就是Intent,过滤器就是IntentFilter。发出消息的组件可以在消息中设置目标组件的相关信息,目标组件也可以设置过滤器,然后系统会进行过滤,只把组件所感兴趣的消息,传递给组件。这里假设读者已经了解Intent和IntentFilter的基本使用方法,且并不会进行全面的介绍,如果不了解,可以先读读官方文档,这里重点讲讲IntentFilter在使用时的一些注意事项。
Intent消息机制通常有二种,一个是显式Intent(Explicit Intent),另一个是隐式Intent(Implicit Intent)。
  • 显式Intent--需要在Intent中明确指定目标组件,也就是在Intent中明确写明目标组件的名称(Component name),需要指定完整的包名和类名。因为对于本程序以外的其他应用程序,你很难知道它的组件名字,所以显式的Intent通常用于应用程序内部通信,更确切的说,显示Intent是用于应用程序内部启动组件,通常又是Activity或Service。还没有见用显式Intent来给BroadcastReceiver发送广播的。
  • 隐式Intent--也就是不在Intent中指定目标组件,在Intent中不能含有目标的名字。系统是根据其他的信息,比如Data,Type和Category去寻找目标组件。
隐式Intent通常用于与应用程序外部的组件进行通信。应用程序级别的组件复用也主要是靠隐式Intent来完成的。而IntentFilter也是只有隐式Intent才用的着,显式Intent都是直接把Intent传递给目标组件,根本不会理会组件的IntentFilter。

显式Intent(Explicit Intent)

显示Intent使用起来比较简单,只需要在Intent中指定目标组件的名字即可,也就是通过Intent的方法设置Component属性。如前所述,显式Intent通常用于应用程序内部启动Activity或Service。事实上,并不完全局限在应用程序内部,对于外部应用的Activity和Service,也可以用显式Intent来启动,但你必须知道它们的名字。
设置组件的名字的方法有:
事实上虽然设置的方法有这么多,但Intent内部标识目标组件的属性只有一个Component,所以这么设置方法的目的也只是设置目标组件的Component,事实上有这么多的方法原因在于ComponentName的构造是多重载了的。在解析Intent时,系统也是取得这个Component属性,然后去启动它。
ComponentName Intent.getComponent();
对于应用程序内部启动Activity通常是这样子设置Intent:
因为应用程序内部的组件类,都是可以访问到的,所以要尽可能少写字串常量,以减少拼写错误,如果一定要使用包名和类名,也要注意,类名必须是全称,也就是从包名开始,如“com.hilton.networks.WifiManagerActivity"。
但是对于外部应用程序的Activity,通常只能通过以下方法:
首先,带有Context为参数的是不能够用的,因为通常你无法拿到其他应用程序的Context,你只能拿到你所在应用程序的Context,所以用你所在的应用程序的Context去启动外部的Activity肯定会报错的。其次,不参再像上面那样通过Class.getName()去指定类名,你为你无法导入外部的类,会有编译错误的。另外,千万要注意不要拼错,否则会有RuntimeException抛出的。
对于Service组件,也是一样,Intent的写法与Activity组件一致,但是对于BroadcastReceiver组件通常都用显式Intent。

隐式Intent的消息过滤器--IntentFilter

IntentFilter是用来解析隐式Intent(Implicit Intent)的,也就是说告诉系统你的组件(Activity, Service, BroadcastReceiver)能够处理哪些隐式的Intent。在使用的时候我们通常是这样子的:
在Manifest中使用IntentFilter时要注意以下三点:
1. 千万注意拼写错误
这里有一个需要十分小心和注意的地方那就是对于IntentFilter里面的Action和Data字串常量不要写错,因为这个在编译时是不会被检查,在运行时又不会抛出异常,如果你拼写错了,比如大小写拼错了,在编译时和运行时都不会有错误,但是你的程序却不能正常工作,你的程序无法收到相应的Intent。曾有一个同事在IntentFilter中写了一些Action,但把其中一个的大小写拼错了,结果花了他一个下午的时间来调试,最后还是另外一个同事到他那聊天才发现了是大小写的拼写错误。
这里也可以发现Android在Manifest文件中的IntentFilter这块的封装性很差。如果,仅仅是如果,这些Action常量也可以通过引用的方式来写,就可以在编译时做些检查和匹配,可以大大的减少出错的机率,同时也加强了封装和信息隐藏。比如,对于上面的可以写成这样:
虽然这种拼写错误很低级,但是因为它低级所以当程序不能正常工作时没有人会想到是因为拼写错误,所以这种拼写错误通常会耗费不少的调试时间。另外一种避免此种错误的方法就是在代码中通过Context.registerReceiver(BroadcastReceiver,IntentFilter)来注册BroadcastReceiver,就可以直接写入常量,而非具体字串。但这只能是接收Broadcast的时候,对于那些想作为公开接口的组件,还是需要在Manifest里面声明,比如Email,它要能处理Intent.ACTION_SEND_TO,就需要在Manifest中声明。2. 要注意Data字段除了上面讨论的之外,对于IntentFilter还有另外的一点需要注意,就是对于某些Action是需要加上Data字段信息,否则有可能接收不到。比如:
对于手机外部存储卡的状态变化的Broadcast,在注册监听器的时候就需要加上DataScheme,否则就会接收不到。这个也花费了我几个小时的调试时间,改在代码中用Context.registerReceiver(BroadcastReceiver,IntentFilter)注册也不行,最后参考了Music中的做法,加上了DataScheme才能在onReceive()中接收到Intent。同样对于后面的Package相关的Broadcast,也是要加上DataScheme否则也是接收不到Broadcast。可悲的是对于像这样的系统公共的Broadcast
Intent,在Intent的文档中并没有说明如何使用,如果没有参考事例,相信需要一定的时间才能够找出为什么接收不到Intent。
除了DataScheme还有一个是MimeType,这个对于系统公共接口是必须加上的,比如Email要处理Intent.ACTION_SENTTO,就需要这样声明:
3. 同时也要注意Category字段
如果没有对IntentFilter写正确的Category字段,也是收不到Intent。比如:
如果把Category去掉,死活也接收不到Intent,当然这要取决于Intent是如何发出的,如果Intent发出时没有加Category,那就没有必须在IntentFilter加上Category。
总之,对于Intent,要保证发出和接收完全一致,否则系统就无法找到相应的匹配,程序也就无法接收Intent。
有关于 DEFAULT category,也要注意,如果是针对Activity的Implicit Intent隐式Intent,如果在没有其他Category的情况下,一定要加上DEFAULT Category。因为系统会在Context.startActivity(Intent)和Context.startActivityForResult(
Intent)时给Intent加上DEFAULT category。而对于Context.sendBroadcast(Intent),Context.sendOrderedBroadcast(Intent),Contxt.sendStickyBroadcast(Intent)和Context.bindService(Intent)Context.startService(Intent)就不会加DEFAULT Category。
另外要注意,尽量把Action进行合并写进一个IntentFilter中。因为对于每个IntentFilter标签都会创建一个IntentFilter对象,所以如果写几个就会有几个对象在那,不但耗费资源而且在匹配的时候也会耗费更多的时间,因为在查询匹配的时候是要一个IntentFilter对象接着一个IntentFilter对象进行检查的。直到找到最佳匹配或是到所有的IntentFilter都检查完为止。

IntentFilter的匹配规则

1. 通过Action字段来匹配这个是Intent中比较基本的一个字段,也比较简单,就是一个字串,如果相等就匹配成功,否则证明还没找到目标。但要注意,如果IntentFilter没有指定Action,那么它不会匹配到任何的隐式Intent,它只能被显式的Intent匹配上。反过来,如果Intent自己没有指定Action,那么它能匹配上含有任何Action的IntentFilter,但不能匹配上没有指定Action的IntentFilter。对于Action,平时要注意拼写错误,因为在AndroidManifest文件中声明Action都是字串,并且在编译时不会做检查,运行时,如果Action拼错了导致匹配不上,要么是程序不能正常工作,要么会有异常抛出。

2. 通过Category字段来匹配对于Activity来讲,如果想处理隐式Intent,并且除了Intent.ACTION_MAIN以外,必须指定Category为DEFAULT,否则不会被匹配到。因为Context.startActivity()和Context.startActivityForResult()会自动加上DEFAULT Category。其他情况,Service和BroadcastReceiver则不会,对于Service和BroadcastReceiver,如果Intent中没有指定Category,那么在其IntentFilter中也不必指定。

3. 通过Data字段来匹配这个相对来讲比较复杂,通常Data包含uri, scheme(content, file, http)和type(mimeType)对于Intent来讲有二个方法:

对于IntentFilter来讲,需要设置的是Scheme和Type,Scheme是对Uri的限制,目标需要限制Scheme是因为Scheme能告诉目录能从哪里拿到Uri所指向的文件,Type是MimeType对类型的限制。
Data匹配时的规则一共有四条:
a.如果Intent没有指定Data相关的字段,只能匹配上没有指定Data的IntentFilter。也就是说如果一个Intent没有指定任何的Data(Uri和Type),它只能匹配到没有指定任何Data(Scheme和Type)的IntentFilter。
b.如果一个Intent只指定了Uri但是没有Type(并且Type也不能够从Uri中分析出)只能匹配到仅指定了相应Scheme且没有指定Type的IntentFilter。实际的例子有如果一个Intent是想要发邮件,或是打电话,它们的Intent是类似这样的:"mailto:someone@sb.com"和"tel:1234567"。换句话说,这些Uri本身就是数据,而不再是一个指向数据的地址。比如:Phone中的Dialer就有如下的IntentFilter:


再如,要处理SD状态变化的IntentFilter:


再如,要处理Package状态变化的IntentFilter:


但是注意,对于想对数据进行操作的Intent,最好不要只指定Uri,而不指定类型。因为如果这样做通常会匹配到一大堆
c. 如果一个Intent只指定了Type,但是没有指定Uri,它只能匹配到只指定了相应Type且没有指定Scheme的IntentFitler
d. 如果一个Intent即有Uri又有Type,那么它会匹配上:1).Uri和Type都匹配的IntentFilter;2).首先Type要匹配,另外如果Intent的Uri是content:或file:,且IntentFilter没有指定Scheme的IntentFilter。因为对于Android来讲content和file这二种Scheme是系统最常见也是用的最多的,所以就当成缺省值来对待。
另外需要注意,Type,因为是MimeType,所以是允许使用通配符的,比如'image/*',能匹配上所有以'image'为开头的类型,也说是说能匹配上所有的图像。

根据Data匹配的例子

假如系统中有四个Activity,A的IntentFilter是这样子的:
这表明A可以发送一切图片类型,并且内容必须是由ContentProvider提供的,也就是Uri必须是以"content://"开头的
而另外一个Activity B是这样子声明的:
这表明B可以发送一切图片,但内容必须是单独的一个文件,也就是Uri必须是由"file://"开头的
还有一个C是这样子声明的:
这表明C只能接收那些没有指定任何Uri和Type的Action是SEND的Intent。
而D是这样子声明的:
这表明D可以发送一切图片,无论是数据库内的(content),还是单独的文件(file)。
如果一个Intent是这样写的:
那么它只能匹配C,因为C没有指定数据和类型,Action是SEND,根据规则a,它只能匹配Activity A。但如果给Intent加上额外的条件
那么如果uri是数据库内容,它会匹配到A,如果它是一个文件,会匹配到B。但无论是content还是file都会匹配到D,因为它能处理以任何形式存储的图片。但始终不会匹配到C,因为C没有声明Data字段,所以不会匹配上。
所以,通常想把组件作为系统公用接口时都是这样子来写:
Intent和IntentFilter对于组件Activity来讲注意事项比较多,但是对于Service和BroadcastReceiver来说就没有那么多的注意事项了,因为对于Service和BroadcastReceiver通常都不用设置Category和Data。但也有例外,比如前面所讲到的SD相关广播和应用程序安装相关广播。
另外要注意,如果使用Context.startActivity()或Context.startActivityForResult(),Context.bindService()和Context.startService(),如果系统没有为Intent匹配到目标Activity和Service那么会有RuntimeException(ActivityNotFoundException)抛出;如果有多个目标同时匹配,会以列表的方式来让用户选择使用哪个。

使用IntentFilter匹配来进行查询可用的组件

Intent和IntentFilter不但可以用来进行组件复用,还可以用于查询系统内都有哪里组件能做哪些事情。比如Launcher上面会列出很多的应用,其实这种说法不准确,应该是上面列出了所有的能启动一个应用的组件(比如,Dialer和Contacts同属于一个应用程序Contacts中,但是在Launcher里面却有二个,一个是Dialer一个是Contacts。那么Launcher是如何做到的呢?它不可能是去检查系统文件,看看哪些应用程序文件存在,然后再列出来。它是通过查询Intent的方式,把所有含有"android.intent.action.MAIN"和"android.intent.category. LAUNCHER"的Activity的相关信息都取出来,然后列出它们的名称和Icon。同样,我们也可这样来获得具体相应特征的组件,具体的请参考SDK中的一篇文章(Resources->Articles->Can I Use this Intent?),讲的很详细,且有Sample Code。



已有 0 人发表留言,猛击->>这里<<-参与讨论


ITeye推荐



]]>
Sun, 13 Nov 2011 20:47:00 +0800 http://www.baidu.comhttp://www.internet-dz.com/blog/1260445 http://www.internet-dz.com/blog/1260445
Hadoop分布式环境下的数据抽样-www.internet-dz.com 1. 问题由来

Google曾经有一道非常经典的面试题:

给你一个长度为N的链表。N很大,但你不知道N有多大。你的任务是从这N个元素中随机取出k个元素。你只能遍历这个链表一次。你的算法必须保证取出的元素恰好有k个,且它们是完全随机的(出现概率均等)?

这道题的解法非常多,网上讨论也非常热烈。本文要讨论的是,这个问题是从何而来,有什么实用价值?

自从有了Hadoop之后,该问题便有了新的应用载体。随着数据量的增多,很多数据挖掘算法被转移到MapReduce上实现,而数据挖掘中有个基本的问题是怎样对数据进行抽样。在Hadoop中,每个job会被分解成多个task并行计算,而数据的总量事先是不知道的(知道job运行结束才能获取数总数,而数据量非常大时,扫描一遍数据的代价非常高),用户知道的只是要获取的样本量,那怎样在类似于Hadoop的分布式平台上进行数据抽样?

回过头来看google的这道面试题,是不是正好时Hadoop平台上海量数据抽样问题?

2. 在Hadoop上编写抽样程序

2.1 解法一

(1) 设计思想

蓄水池抽样:先保存前k个元素, 从第k+1个元素开始, 以k/i (i=k+1, k+2,…,N) 的概率选中第i个元素,并随机替换掉一个已保存的记录,这样遍历一次得到k个元素,可以保证完全随机选取。

(2) MapReduce实现

要实现该抽样算法,只需编写Mapper即可。在Map函数中,用户定义一个vector保存选中的k个元素,待扫描完所有元素后,在析构函数中将vector中的数据写到磁盘中。

用户运行job时,需指定每个map task的采样量。比如,该job的map task个数为s,则每个map task需要采集k/s个元素。

(3) 优缺点分析

由于该job没有reduce task,因而效率很高。然而,该方法选中某个元素的概率并不完全是k/N!

2.2 解法二

(1) 设计思想

依次扫描每个元素,为每个元素赋予一个随机的整数值;然后使用Top K算法(譬如最大K个整数)得到需要的K个元素。

(2) MapReduce实现

要实现该算法,用户需要编写mapper和reducer,在map函数中,为每个元素赋予一个随机数,将该随机数作为key,并将key最大的前k个保存下来(可使用小顶堆)在reduce函数中,唯一的reduce task输出前k个元素。

(3) 优缺点分析

该算法比第一种算法低效,但由于整个过程自然流畅,实现起来非常简单,不易出错。

2.3 解法三

(1) 设计思想

考虑第一个元素,其以K/N的概率被选中;如果该节点被选中,则从剩下的(N-1)个元素中选出(K-1)个元素;如果没有被选中,则从剩下的(N-1)个元素中选出K个元素,…,依次这样下去,直到获取K个元素。

(2) MapReduce实现

用户只需编写Mapper即可。首先要获取每个map task输入的数据量,这个可以在InputFormat中计算得到。然后,在每个map函数中,采集k/s(其中s为map task数据量)个元素。

(3) 优缺点分析

由于该算法没有reduce task,效率比较高,但需要在InputFormat中统计数据量,编程复杂度较高。

3. 延伸

这个问题与《编程珠玑》上讨论的问题很相似:

输入两个整数m和n,其中m<n。输出是0~n-1范围内m个随机整数的有序表,不允许重复。

对于该问题,大致存在四种算法,他们有不同的优缺点。

(1) 第一种方法来自Knuth的《The art of Computer Programming, Volume 2: Seminumerical Algorithms》

伪代码是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
select = m
remaining = n
for I = [0 n )
if(bigrand() % remaining) < select
print i
select—
remaining—

只要m<=n,程序选出来的整数就恰为m个。

C++的实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void genKnuth(int m, int n) {
for(inti = 0; i < n; i++) {
if(bigrand() % (n - i) < m) {
cout <<i << endl;
m--;
}
}
}

该算法非常节省空间,但需要全部扫描n个数,当n很多时,效率不高。

(2)第二种方法的复杂度只与m有关,采用了set(实际上是红黑树)节省时间。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void gensets(int m,intn) {
set<int> S;
while(S.size() < m) {
S.insert(bigrand() % n);
}
// print S
}

该方法每次插入均在O(log m)时间内完成,但需要的空间开销很大。

(3)第三种方法克服了(2)的缺点,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
void genshuf(int m,intn) {
inti, j;
int*x =new int[n];
for(i = 0; i < n; i++) {
x[i] = i;
}
for(i = 0; i < m; i++) {
j = randint(i, n-1);
intt = x[i]; x[i] = x[j]; x[j] = x;
}
sort(x, x+m);
//print result
}

该算法需要n个元素的内存空间和O(n+mlogm)的时间,其性能通常不吐Knuth的算法。

(4)当m接近n时,基于集合的算法生成的很多随机数都要丢掉,因为之前的数已经存在于集合中了,为了改进这一点,算法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void genfloyd(int m, int n)
{
set<int> S;
set<int>::iterator i;
for(intj=n-m; j < n; j++) {
intt = bigrand()%(j+1);
if(S.find(t) == S.end()){
S.insert(t);// t not in S
}else{
S.insert(j);// t in S
}
}
//print results
}

4. 参考资料

(1) 《编程珠玑》第二版

(2) http://www.internet-dz.com/amyh5163sjb/sunxiangwei/blog/item/a7839b51bdbf522e42a75b45.html

本文链接地址: http://www.internet-dz.com/amyh5163sjb/data-mining/hadoop-sampling/



已有 0 人发表留言,猛击->>这里<<-参与讨论


ITeye推荐



]]>
Sun, 13 Nov 2011 11:18:00 +0800 http://www.baidu.comhttp://www.internet-dz.com/blog/1260935 http://www.internet-dz.com/blog/1260935
linux下查看系统资源和负载,以及性能监控-www.internet-dz.com 1,查看磁盘

df -h

2,查看内存大小

free

free [-m|g]按MB,GB显示内存

vmstat

3,查看cpu

cat /proc/cpuinfo

只看cpu数量grep "model name" /proc/cpuinfo | wc -l

4,查看系统内存

cat /proc/meminfo

5,查看每个进程的情况

cat /proc/5346/status 5347是pid

6,查看负载

w

uptime

7,查看系统整体状态

top

最后一些输出信息的解释:

loadaverage:0.09,0.05,0.01

三个数分别代表不同时间段的系统平均负载(一分钟、五 分钟、以及十五分钟),它们的数字当然是越小越好。“有多少核心即为有多少负荷”法则: 在多核处理中,你的系统均值不应该高于处理器核心的总数量

进程使用的内存可以用top,有3个列 VIRT RES SHR, 标示了进程使用的内存情况, VIRT标识这个进程可以使用的内存总大小, 包括这个进程真实使用的内存, 映射过的文件, 和别的进程共享的内存等. RES标识这个这个进程真实占用内存的大小. SHR标识可以和别的进程共享的内存和库大小.

8,性能监视sar命令

sar -u输出显示CPU信息。-u选项是sar的默认选项。该输出以百分比显示CPU的使用情况


CPU

CPU编号

%user

在用户模式中运行进程所花的时间

%nice

运行正常进程所花的时间

%system

在内核模式(系统)中运行进程所花的时间

%iowait

没有进程在该CPU上执行时,处理器等待I/O完成的时间

%idle

没有进程在该CPU上执行的时间


sar 5 10 sar以5秒钟间隔取得10个样本

sar -u -p ALL 5 5 分cup显示

sar -n { DEV | EDEV | NFS | NFSD | SOCK | ALL }

sar 提供六种不同的语法选项来显示网络信息。-n选项使用6个不同的开关:DEV | EDEV | NFS | NFSD | SOCK | ALL 。DEV显示网络接口信息,EDEV显示关于网络错误的统计数据,NFS统计活动的NFS客户端的信息,NFSD统计NFS服务器的信息,SOCK显示套接字信息,ALL显示所有5个开关。它们可以单独或者一起使用。

sar -n DEV 各参数含义

IFACE

LAN接口

rxpck/s

每秒钟接收的数据包

txpck/s

每秒钟发送的数据包

rxbyt/s

每秒钟接收的字节数

txbyt/s

每秒钟发送的字节数

rxcmp/s

每秒钟接收的压缩数据包

txcmp/s

每秒钟发送的压缩数据包

rxmcst/s

每秒钟接收的多播数据包

9,查看命令历史(含时间戳)

export HISTTIMEFORMAT='%F %T ';history| more


10,查看文件夹和文件大小

du -h --max-depth=0 dm 查看dm目录大小

du -h --max-depth=1 dm 查看dm目录大小,以及dm各文件文件夹的大小

du -h --max-depth=0查看当前文件夹大小



澳门银河5163手机版


ITeye推荐



]]>
Sun, 13 Nov 2011 10:38:00 +0800 http://www.baidu.comhttp://www.internet-dz.com/blog/1260936 http://www.internet-dz.com/blog/1260936