Resive world

Come world to Record life


  • Home

  • Tags

  • Categories

  • Archives

  • Sitemap

  • Search

Ubuntu下配置Tomcat服务器

Posted on 2016-01-21 | In Java

本来以为安装了apache之后就可以万事大吉了,没想到在用java的时候发现apache并不能执行servlet服务,也不能解析jsp。想实现这些功能就得安装Apache的一个拓展服务器--Tomcat。

与apache的差别

这个Tomcat其实可以看成是apache的一个拓展,他能实现上述apache服务器实现不了的东西。但是他也有不足,那就是他不能解析php,而且据说解析网页的速度也没有apache快,也没有apache稳定。所以说他并不能代替apache,apache也不能代替他。事实上他和apache虽说是两个服务器,但却是能很好的兼容的,因为apache的默认端口是80,而Tomcat的默认端口是8080(当然这是可以修改的),所以并不冲突。

下载安装

首先从apache的Tomcat官网上找到需要下载的源码。这里注意搭配环境,8.0的版本是要支持JDK1.7的,而9.0的版本是要支持JDK1.8的。这里我是JDK1.7所以只能用8.0的。

(这里需要注意一下,我们最好下Core版本,而不要下src源码版本。因为src版本里面缺少一些必要的jar包,在启动服务的时候会报错,还得回官网来下载/bint/extra里面的包。。。)

下载下来后按理说应该找README文件,但是这里没有。最后浏览了下找到了RUNNING.txt文件,打开一看,大概就是我需要的安装向导了。

根据安装向导做出了以下配置:

1、设置CATALINA_HOME环境变量:

这个变量是给系统寻找tomcat文件目录用的,会在他的脚本里面调用,所以有必要设置成环境变量,在/etc/envirenment里面根据格式加上他的文件地址就可以了。这里还有一个CATALINA_BASE变量可以写,不过既然默认是和CATALINA_HOME一样,那就暂且忽略他吧。

2、设置配置文件:

根据提示找到了$CATALINA_HOME/bin/catalina.sh文件,里面讲了一大堆可以设置的变量,但是必选的只有两个,一个是上面提到的,另一个就是$JAVA_HOME变量了。不过他建议我们把这些用户写的变量统一写到setenv.sh下面便于管理,那我们就照做吧。在同文件下新建setenv.sh文件并写入$JAVA_HOME变量的地址(/usr/lib/jvm/java-7-openjdk-amd64/)。

设置之后记得source /etc/envirenment执行一下文件。

3、执行安装文件:

找到start.sh,给予执行权限然后执行。我这里报了一个错,说找不到logs文件夹。。。。不晓得那个启动脚本怎么都没考虑到这一点。。找不到新建一个不就好了么。。。

执行成功后他显示了Tomcat started. 。

4、启动脚本:

事实上tomcat的启动脚本是catalina.sh,所以我们可以通过./catalina.sh  start 和 ./catalina.sh stop 来启动和关闭服务。既然如此,那么我们何不把他移到/etc/init.d里面去用service命令来操作呢?用一个软链接加进去就好了sudo ln -s /usr/local/tomcat/ibn/catalina.sh tomcat  。

这样就可以方便的进行管理了。

测试

打开浏览器访问localhost:8080即可看到测试页面了。

service命令的原理以及init.d启动脚本的格式

Posted on 2016-01-20 | In Linux

我们在启用一些服务的时候,经常会用到这个service命令,比如启动apache2的命令$sudo service apache2 start等等。用他来开启或者关闭我们的服务可谓是非常的方便,因为service命令基本都会支持start、stop、restart之类的参数,十分的好记。

作用原理

那么service命令的原理是什么呢?为什么他能做到这么统一的样式呢?

其实答案很简单,我们来查看帮助文档就知道了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$man service
......
service runs a System V init script or upstart job in as predictable an
environment as possible, removing most environment variables and with
the current working directory set to /.

The SCRIPT parameter specifies a System V init script, located in
/etc/init.d/SCRIPT, or the name of an upstart job in /etc/init. The
existence of an upstart job of the same name as a script in /etc/init.d
will cause the upstart job to take precedence over the init.d script.
The supported values of COMMAND depend on the invoked script. service
passes COMMAND and OPTIONS to the init script unmodified. For upstart
jobs, start, stop, status, are passed through to their upstart equiva‐
lents. Restart will call the upstart 'stop' for the job, followed imme‐
diately by the 'start', and will exit with the return code of the start
command. All scripts should support at least the start and stop com‐
mands. As a special case, if COMMAND is --full-restart, the script is
run twice, first with the stop command, then with the start command.
This option has no effect on upstart jobs.
......

上面这段话已经说了很清楚了,这个service命令,会去查找/etc/init.d/和/etc/init/目录下的可执行脚本。这些脚本通常保证得实现start,stop,status之类的命令来实现相应的功能。也就是说,我们通常类似service apache2 start的命令完全可以用/etc/init.d/apache2 start来代替,效果一模一样。

其实他做的事情就是这么简单,一般就是去/etc/init.d/目录下寻找脚本来执行。所以问题的重点就变成了这些脚本到底是什么样的。

这就牵涉到/etc/init.d/下的启动脚本格式的问题了。

启动脚本

本着自力更生的原则,自己查看man文档,在service命令的末尾他给了一个/etc/init.d/skeleton文件叫我们看。那就打开来看看喽~~:

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#! /bin/sh
### BEGIN INIT INFO
# Provides: skeleton
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Example initscript
# Description: This file should be used to construct scripts to be
# placed in /etc/init.d.
### END INIT INFO

# Author: Foo Bar <foobar@baz.org>
#
# Please remove the "Author" lines above and replace them
# with your own name if you copy and modify this script.

# Do NOT "set -e"

# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="Description of the service"
NAME=daemonexecutablename
DAEMON=/usr/sbin/$NAME
DAEMON_ARGS="--options args"
PIDFILE=/var/run/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME

# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0

# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME

# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh

# Define LSB log_* functions.
# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
# and status_of_proc is working.
. /lib/lsb/init-functions

#
# Function that starts the daemon/service
#
do_start()
{
# Return
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
|| return 1
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \
$DAEMON_ARGS \
|| return 2
# Add code here, if necessary, that waits for the process to be ready
# to handle requests from services started subsequently which depend
# on this one. As a last resort, sleep for some time.
}

#
# Function that stops the daemon/service
#
do_stop()
{
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME
RETVAL="$?"
[ "$RETVAL" = 2 ] && return 2
# Wait for children to finish too if this is a daemon that forks
# and if the daemon is only ever run from this initscript.
# If the above conditions are not satisfied then add some other code
# that waits for the process to drop all resources that could be
# needed by services started subsequently. A last resort is to
# sleep for some time.
start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
[ "$?" = 2 ] && return 2
# Many daemons don't delete their pidfiles when they exit.
rm -f $PIDFILE
return "$RETVAL"
}

#
# Function that sends a SIGHUP to the daemon/service
#
do_reload() {
#
# If the daemon can reload its configuration without
# restarting (for example, when it is sent a SIGHUP),
# then implement that here.
#
start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
return 0
}

case "$1" in
start)
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
do_start
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
stop)
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
do_stop
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
status)
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
;;
#reload|force-reload)
#
# If do_reload() is not implemented then leave this commented out
# and leave 'force-reload' as an alias for 'restart'.
#
#log_daemon_msg "Reloading $DESC" "$NAME"
#do_reload
#log_end_msg $?
#;;
restart|force-reload)
#
# If the "reload" option is implemented then remove the
# 'force-reload' alias
#
log_daemon_msg "Restarting $DESC" "$NAME"
do_stop
case "$?" in
0|1)
do_start
case "$?" in
0) log_end_msg 0 ;;
1) log_end_msg 1 ;; # Old process is still running
*) log_end_msg 1 ;; # Failed to start
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
*)
#echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
exit 3
;;
esac

:

哦~原来这就是所有init.d目录下脚本的框架了~~难怪他能保证良好的兼容性,原来所有的service原则上都是从这个框架上生成的。。。这个文件看上去挺长的,其实内容很少,主要就是一个case语句根据相应的参数进行不同的输出。这里不做过多讨论,以后需要自己写一个启动脚本的时候再来研究也不迟。

screen命令基本用法详解

Posted on 2016-01-19 | In Linux

在服务器上搭建一些服务的时候,经常要用到screen命令。这是因为一般情况下我们只会开一个连接服务器的控制台,但是某些服务(比如minecraft服务器)开启的时候需要占据一整个控制台,如果关闭了就会导致进程终止。这就成了类似单进程的效果。而screen命令就是为了能够在服务器上开启多个控制面板(screen),用以容纳不同的任务。

安装

ubuntu软件库里就有,直接下载:

1
$sudo apt-get intstall screen

基本概念

话说我看了网上很多的教程,发现他们大多是把命令啊参数啊什么的列一遍,却并没有告诉我他这里不同窗口的关系,导致被screen耍的云里雾里的。在蛋疼了好久之后,我终于大概晓得了他实质的运作机制(估计是我开始想偏了)。。。

首先我们要明确三个窗口的概念(话说这三个窗口我是摸索了好就才理清楚的~~~汗。。)

默认窗口

所谓默认窗口就是我们没有用screen命令时的那个干干净净的窗口,不能使用等会介绍的screen命令下的任何快捷键。(这个不是废话)

screen界面

screen界面就是当我们进入screen空间下的,占用了一个进程pid的一个界面。这个界面有他自己的名字,有他自己内部交互的快捷键,能够拥有很多不同的子终端的界面。也可以理解成独立于默认窗口之外的窗口。注意,是每一个screen界面都能拥有很多的子窗口,而我们的电脑能同时拥有很多不同的screen界面。

子窗口

每一个子窗口都是附属与一个screen界面下的,他们互不影响,能够分别执行不同的命令,这是整个screen命令的精华所在。工作时,我们需要做的就是选定某一个screen,并且选定一个子窗口。这样如果我们需要换一个界面的话,我们就只需要更换另一个子窗口就行了。

可能不太清楚,但是只要晓得有这么三个层次就好了(不要当成只有两个层次!!)

基本命令

既然有了三个层次,那么我们是不是要考虑三种不同的窗口下的命令呢?其实不是,因为每一个screen都得有至少一个的子窗口,所以我们只要考虑两个层次下的命令就可以了,一个是面对不同screen界面的切换,另一个是面对同一个screen界面下不同终端之间的切换。

面向screen级别的命令

1、新建一个screen :

可以直接输入screen 来打开一个带有默认名字的screen界面,也可以加上 -S 参数来亲自制定一个好听的名字。然后系统就会切进当前的screen了。

2、查看当期存在的screen:

输入screen -ls 可以查看当前存在的screen 界面,比如:

1
2
3
4
5
6
myths@Business:~$ screen -ls
There are screens on:
4545.s2 (2016年01月19日 19时40分28秒) (Attached)
4506.s1 (2016年01月19日 19时40分22秒) (Detached)
4487.pts-8.Business (2016年01月19日 19时40分15秒) (Attached)
3 Sockets in /var/run/screen/S-myths.

他会显示当前的每一个screen界面,对于每一个界面,他的显示格式是:pid.name (time) (status) ,前面的不解释,最后的那个状态有(Attached) 和(Detached) ,表示是否已经连接进来(?其实不太懂这个意思,没有连接进来那就连接进来呗~有啥必要非得分开看呢。。。不过有一个明显的区别就是,当你断开主界面然后重新登录的时候,所有的screen都是显示Detached的。而如果你想进入某一个screen,你首先得把他的状态变成Attached才行)。

3、关闭和选择screen:

想要关闭一个screen 就要先选择并且进入这个screen。

首先用screen -ls查看你想要选的screen:

如果他的状态是Detached的,我们需要输入screen -r <screen的pid> ,来进入这个screen ;

如果他的状态是Attached的,我们就要输入 screen -d <screen的pid> ,来使他”Dettached”,然后再输入screen -r <screen的pid> ,来进入这个screen。(必须先detached,否则是进入去的)。

进入了你想要关闭的screen之后,就可以直接输入exit,或者Ctrl+d,来终止这个界面了。成功终止后,如果有其他处于Attached状态的screen界面,他就会跳到那个界面中,如果没有,他就会跳到默认界面上。

4、清除损坏的screen :

如果由于某些情况导致一个screen的状态处于Dead(很可能是程序出错或者强行删除进程锁之类的。。),我们无法attached进去,那么我们只需要输入screen --wipe ,就可以删除这些进程了。

面向子窗口切换的快捷键:

在一个screen下,我们可以方便的创建多个子窗口,这些窗口之间转换的操作都是通过Ctrl+a再加参数的组合快捷键实现的。

1、新建子窗口:

可以通过Ctrl+a+c 组合快捷键在当前的screen下创建一个新的子窗口,并跳转到上面去。

2、查询当前的子界面状态:

可以通过Ctrl+a+w组合快捷键,在屏幕的左下角就会出现类似:0-$ bash 1*$ bash 之类的样式。这个表示当前screen下有两个子窗口,当前在的是1号子窗口。当然,这个子窗口的数目可以有很多。

3、切换子窗口:

方法很多,可以通过Ctrl+a+a组合快捷键在最近的两个窗口中切换,也可以用Ctrl+a+n 切换到下一个窗口,或是Ctrl+a+p 切换到上一个窗口,或是Ctrl+a+num 切换到第num个窗口。。。

4、锁定当前窗口:

可以用Ctrl+a+x 来锁住当前的界面,此时所有的快捷键都无法使用,直到输入了密码。。

5、关闭当前窗口:

这个可以直接用Ctrl+d  或者exit 来关闭,当这个窗口是现有screen的最后一个窗口时,就会触发上面讲的关闭当前screen的事件了。

6、暂离当前screen:

这个也是screen命令的精髓,用组合键Ctrl+a+d 就能detached当前的screen,回到默认界面。

大概就是这些操作,其实还挺绕人的,有个小注意点,就是我们可以通过Ctrl+a+w 命令来测试下当前窗口是不是处于screen状态下,如果不是的话,贸然使用Ctrl+a+d 可是会直接退出登陆的额。。

配置apache把子目录设置为二级站点

Posted on 2016-01-15 | In Apache

话说这个教程在网上找了半天硬是都不对,研究半天终于找到一个真正可行的方法,赶紧记一下。。

配置域名解析

这个不用多说了,其实在申请解析域名的时候一般都做好了。这里就是提醒一下,我们需要在域名解析服务商那里,把我们需要添加的所有二级站点作为A记录加进去。如果闲麻烦也可以把*作为A记录加进去,不过A记录只能记录IP,而不是URL,所以并不能实现二级站点的绑定。顺便说一下,其实有很多域名解析提供商或者主机提供商会提供将二级站点绑定到子目录的功能,这倒是挺方便的。然而我买的阿里云的主机配的万网的解析并没有提供这个功能,所以一切还得自己配置。虽然阿里云貌似提供了教程,可是他那个教程也就是教你怎么弄301重定向,然而301重定向只能实现网页的跳转,在浏览器的地址栏上还是会显示丑陋的子目录名,跟二级站点的功能还差得远呢。

设置虚拟主机

让我们重新审视一下apache的配置文件,打开/etc/apache2/sites-enabled/000-default.conf 文件(其实是一个指向/etc/apache2/sites-avaliable/000-default.conf 的软连接),并且扒掉长长的注释,会的到下面的文件:

1
2
3
4
5
6
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html/
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

注意到头标签上的*:80,这就是问题的关键。apache2其实本来就是支持各种主机名的,要不然为什么会用通配符来通配所有80端口的web访问呢。于是就结合现有的资料试着改了下文件:

1
2
3
4
5
6
7
<VirtualHost www.mythsman.com:80>
ServerName www.mythsman.com
ServerAdmin dqz48548263@qq.com
DocumentRoot /var/www/html/
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

把虚拟主机的通配符去掉,用我指定的主页面,然后加一个ServerName 字段告诉主机他自己的名字(有没有必要不晓得),然后将ServerAdmin字段设置为自己的邮箱(写着玩的,理论上讲会收到通知,然而并没有受到过),后面的文档根目录和log输出位置保持不变。

好,修改完成,重启服务,然后记得要清除一下浏览器的缓存,因为有时候服务器会为了效率,在网页没变的情况下把缓存的页面发过去(即304缓存命中无需更新)。结果发现网页果然没出毛病。很好,猜想是对的,接下来应该只要依葫芦画瓢把其他的子页面放进去,并把DocumentRoot字段改成实际的子目录就好了。

下面的文件是将网站根目录下的wordpress/站点、JudgeOnline/站点和/usr/share/下的phpmyadmin/管理站点设置为二级目录的配置方案(当然www站点也会保留为博客入口):

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
29
<VirtualHost www.mythsman.com:80>
ServerName www.mythsman.com
ServerAdmin dqz48548263@qq.com
DocumentRoot /var/www/html/
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
<VirtualHost blog.mythsman.com:80>
ServerName blog.mythsman.com
ServerAdmin dqz48548263@qq.com
DocumentRoot /var/www/html/wordpress
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
<VirtualHost oj.mythsman.com:80>
ServerName oj.mythsman.com
ServerAdmin dqz48548263@qq.com
DocumentRoot /var/www/html/JudgeOnline
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
<VirtualHost mysql.mythsman.com:80>
ServerName mysql.mythsman.com
ServerAdmin dqz48548263@qq.com
DocumentRoot /usr/share/phpmyadmin
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
1,1 Top

ok,试着登陆了一下,果然都是可以访问的,而且浏览器的地址栏都会保留着前面的域名不会变。

设置301跳转

按理说照着上面弄就可以了,但是这样也有一个小漏洞,就是如果仍然直接访问带子目录的地址,网站还是会以子目录的形式表示我的二级站点。也就是说他并不能把类似www,mythsman.com/JudgeOnline/的二级站点自动识别为oj.mythsman.com。解决的方法也很简单,就是利用.htaccess文件为他设置301重定向。这样无论以何种形式访问带子目录的地址都会转到最新的二级域名的形式上,这样良好的保证了域名的兼容性。将下面的文件命名为.htaccess保存在站点的根目录下:

1
2
3
4
5
6
7
8
9
10
11
12
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.mythsman.com$ [NC]
RewriteCond %{REQUEST_URI} ^/JudgeOnline/(.*)$ [NC]
RewriteRule ^(.*)$ http://oj.mythsman.com/%1 [R=301,L]

RewriteCond %{HTTP_HOST} ^www\.mythsman.com$ [NC]
RewriteCond %{REQUEST_URI} ^/wordpress/(.*)$ [NC]
RewriteRule ^(.*)$ http://blog.mythsman.com/%1 [R=301,L]

RewriteCond %{HTTP_HOST} ^www\.mythsman.com$ [NC]
RewriteCond %{REQUEST_URI} ^/phpmyadmin(/)?(.*)$ [NC]
RewriteRule ^(.*)$ http://mysql.mythsman.com/%1 [R=301,L]

文件的写法参照《apache中的htaccess文件格式简析》。有一个注意点,就是由于我的phpmyadmin在网站的根目录下并不存在,所以要考虑下最后有没有/符号。对于其他的页面其实不用考虑,因为就算没有被识别,最终都会由于的确存在这个目录被apache自动识别而再被重定向。所以对于不在根目录下的文件要考虑最后的/符号。

OK,这样就算是成功弄好了二级站点了,域名果然比之前的清楚了许多。

apache中的htaccess文件格式简析

Posted on 2016-01-14 | In Apache

学apache 就必须要学下htaccess。这个在网站比较小的情况下看不出来,但是当网站结构复杂的时候,我们就需要对访问进来的域名进行分类处理了,比如构建二级域名、设置301重定向、404禁止访问的显示界面,设置权限、防止盗链等一系列工作,都需要有.htaccess文件的处理。

概述

.htaccess文件(或者”分布式配置文件”(hypertext access))提供了针对目录改变配置的方法, 即,在一个特定的文档目录中放置一个包含一个或多个指令的文件, 以作用于此目录及其所有子目录。

位置

理论上讲,.htaccess应该存在于站点能访问到的所有文件夹下,但是这样显然可能造成性能和安全上的问题。所以有时候不推荐直接以.htaccess文件的形式保存,而是将他写在apache的总配置文件中( 标签内)。不过,为了稳定性,一般也不想随便修改配置文件,所以这里还是用.htaccess文件来设置。我就直接把.htaccess文件放在我网站的根目录下了(/var/www/html/.htaccess),这样也方便以后的修改。

配置

首先需要给apache2引入rewrite模块,这个默认是没有开启的。输入$sudo a2enmod ,然后他会提示输入模块名,输入rewrite 即可。

然后还要做一个配置,就是在apache2的配置文件(/etc/apache2/apache2.conf)中先设置下,就是将中的 AllowOverride None 设置为AllowOverride All 。这也很好理解,因为.htaccess在某种程度上就是配置文件的扩展喽,所以要允许他来覆盖配置文件。

偶然见看下配置文件后面的内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
# AccessFileName: The name of the file to look for in each directory
# for additional configuration directives. See also the AllowOverride
# directive.
#
AccessFileName .htaccess

#
# The following lines prevent .htaccess and .htpasswd files from being
# viewed by Web clients.
#
<FilesMatch "^\.ht">
Require all denied
</FilesMatch>

以前没有注意过,现在一看才发现,这都是套路啊。凭什么这个文件非得叫.htaccess文件呢?原来他是写在了apache2.conf中了!那么我是不是也可以把这个名字改一下呢~~

而且,为了保证这个文件不被非法访问到,他也预先设置了禁止访问的权限~~想的也是挺周到的。

OK,接下来来看看.htaccess的语法了(其实就是apache2配置文件的语法了)。

语法

举个例子:

1
2
3
4
5
6
7
RewriteEngine On                                   #这句话是方便我们开启下面的部分,可以设置为On 或 Off 这样就不用一句一句注释了。
RewriteBase /          #这句话是把当前的目录看成是网站的根,方便下面的书写。
RewriteCond %{HTTP_HOST} ^(www\.)?xxx\.com$ [NC] #过滤主机名符合后面正则表达式的网址,满足后执行下一步。NC表示忽略大小写。
RewriteCond %{REQUEST_URI} !^/blog/ #过滤URI满足正则表达是的地址,满足后执行下一步。
RewriteCond %{REQUEST_FILENAME} !-f #测试访问的文件是否存在,存在则执行下一步。
RewriteCond %{REQUEST_FILENAME} !-d #测试访问的目录是否存在,存在则执行下一步。
RewriteRule ^(.*)$ blog/$1 [L] #将请求的地址改为blog/(原地址) (301重定向), L 表示条件终止。

从上面的解释也大概也应该晓得的差不多了,就是命令后面一般接两个参数或者再接一个用中括号引用的标签,其中第二个参数多是用正则写的,正则忘了看这里,最多加一个 ! 表示否定。

这当中用到了一些类似%{HTTP_HOST}之类的貌似全局变量的东西,这些东西被称为CGI变量。

!!!这里还要注意一点,就是$1匹配的是RewriteRule里捕获的值,如果想要捕获RewriteCond里捕获的值就得用%1。。。。。。好坑。。。

下面着重讲解下RewriteCond的一些标签:

标记 含义 描述
R Redirect 发出一个HTTP重定向
F Forbidden 禁止对URL地址的存取
G Gone 标记URL地址不存在
P Proxy 将URL地址传递给mod_proxy
L Last 停止处理接下来的规则
N Next 再次重第一个规则开始处理,但是使用当前重写后的URL地址
C Chain 将当前的规则和紧随其后的规则链接起来
T Type 强制执行指明的MIME类
NS Nosubreq 只在没有任何内部子请求执行时运行本脚本
NC Nocase URL地址匹配对大小写不敏感
QSA Qsappend 在新的URL地址后附加查询字符串部分,而不是替代
PT Passthrough 将重写后的URL地址传递给另一个Apache模块进行进一步处理
S Skip 忽略之后的规则
E Env 设置环境变量

这些参数是写在每行后面,用中括号扩起来,如果有多个,则中间用逗号隔开。

下面是RewriteCond的一些参数:

|参数|含义|解释|
|-|-|
|-d|目录|将TestString视为一个路径名并测试它是否为一个存在的目录。|
|-f|常规文件|将TestString视为一个路径名并测试它是否为一个存在的常规文件。|
|-s|非空的常规文件|将TestString视为一个路径名并测试它是否为一个存在的、尺寸大于0的常规文件。|
|-l|符号连接|将TestString视为一个路径名并测试它是否为一个存在的符号连接。|
|-x|可执行|将TestString视为一个路径名并测试它是否为一个存在的、具有可执行权限的文件。该权限由操作系统检测。|
|-F|对子请求存在的文件|检查TestString是否为一个有效的文件,而且可以在服务器当前的访问控制配置下被访问。它使用一个内部子请求来做检查,由于会降低服务器的性能,所以请谨慎使用!|
|-U|对子请求存在的URL|检查TestString是否为一个有效的URL,而且可以在服务器当前的访问控制配置下被访问。它使用一个内部子请求来做检查,由于会降低服务器的性能,所以请谨慎使用!|

以上就是常用的一些语法,当然,htaccess文件可以写的东西远不止这些。

vim高级用法之taglist插件

Posted on 2016-01-13 | In Linux

之前有了ctags的基础,我们就可以实现另外一项炫酷的功能了。我们都知道在类似eclipse之类的ide中,都有能够显示当前函数和变量的outline窗口。能非常清楚的看出程序的架构,而且也方便程序员寻找。好了,开始迈出vim插件之旅的第一步。

下载安装

话说到现在我才知道原来vim有他的官网的:www.vim.org,在这里照script条目就可以看到5000多个的插件了,搜索下taglist就可以找到最新的版本了:taglist_46.zip。

下载下来并解压会有两个文件夹,doc/和plugin/。意图很明显了。我们只要把他们放到~/.vim路径下对应的文件夹里就行了(如果没有对应的文件夹就创建一个)。

搞定后打开一个vim,在行末模式下输入::helptags ~/.vim/doc/,这样就能用:help taglist.txt来查看帮助文档了。

vim中的简单配置

首先当然是要简单配置一下了,直接上代码,已经注释的很清楚了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
""""""""""""""""""""""""""""""""""
" Taglist
"set mouse=a "这个设置是必须的,这样才能点击标签
let Tlist_Ctags_Cmd = 'ctags' "设置ctags命令的路径
let Tlist_Show_One_File = 1 "不同时显示多个文件的tag
let Tlist_Exit_OnlyWindow = 1 "如果taglist是当前最后一个窗口则退出vim
let Tlist_Use_Right_Window = 1 "设置窗口位置为右边(默认在左>边)
let Tlist_Sort_Type='name' "设置Tlist的排序方式为按名称排序,默认为按出现顺序
let Tlist_Use_SingleClick=1 "设置单击一次tag即跳转到定义,默认为双击
"let Tlist_Auto_Open = 1 "设置开启vim自动打开Tlist
"let Tlist_Close_On_Select = 1 "设置在选择tag后自动关闭Tlist}
let Tlist_Process_File_Always=1 "在不显示Tlist的时候仍然解析tags
nnoremap <silent> <F8> :TlistToggle<CR> "映射F8为打开和关闭Tlist的快捷键(在normal模式下)

""""""""""""""""""""""""""""""""""

当然在不配置的情况下,在行末模式下输入:TlistOpen可以打开窗口。

效果图

另外,使用后发现其实效果并没有想象中那么好。界面比较丑,非全屏模式下丑的不能看,而且代码识别的相应程度也不好,必须要先保存文件他才会识别。不过如果熟练掌握了应该也是一个很强大的东西吧。

利用chrome下载微信公众号上的音乐

Posted on 2016-01-12 | In Web

不知道怎么的,突然江苏的几所大学就盛行一个改编《南山南》的风气,各个学校都争相在自己的官微上发布自己改编的《南山南》。好好的一首歌就这么被乱改我也是挺心痛的。不过话说回来,当我想在电脑上听歌的时候突然发现电脑竟然无法听歌,更别提下载了。下面就以南航的官微页面为例。

修改User-agent

首先解决下听的问题,其实听的问题还是很普遍的。如果注意的话,你会发现很多能用手机打开的网页在电脑上打开的时候就会出现类似无法点击的异常情况。比如他的下载界面:

下面播放的地方是无法点击的,这是因为那些网页本来就是提供给他的客户端看的,并不需要能在电脑上看。因此他在设计的时候就没有考虑电脑的接口,于是就直接将客户认定为手机端。这样一来用电脑当然不能触发一些滑动、触摸的事件了。

解决的方法也很简单啦,毕竟我们的chrome 是很强大的,在开发者工具里就有一个用来模拟移动端设备的调试模式:

按F12 进入开发者模式后,点击左上脚的那个“小手机”的图标,进入模拟设备的模式。然后会在下面看到Emulation框已经激活。(当然也可以直接Enable emulation)。选择Device条目,将Model改为我们需要模拟的手机。接着就会在左边出现一个类似手机屏幕的框框,而且鼠标也变成了移动端的滚动球,这样就OK了。当然如果不想看这么小的屏幕,我们可以把下面的Enable screen resolution选项关掉(默认是开的)。

最后我们点开Network条目,会发现其中有一个填写User-agent的框框,而且已经被填上了类似:

1
Mozilla/5.0 (Linux; Android 4.3; Nexus 10 Build/JSS15Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2307.2 Safari/537.36

之类的移动端的User-agent了。这样我们就发现能点的动播放歌曲的按钮了。

下载音频

查阅了一下资料,发现原来主要是考虑到版权的原因,所以不能提供下载链接。所以他的播放地址并不像平常的地方一样把url直接写在源码的显眼位置。而是藏在他硕大的js 文件里。显然,这对通过人脑识别地址的方法有一定的限制作用。然而,我们有chrome的过滤系统,任何偷偷与后台交互的数据都逃不掉。在network条目中,我们可以通过过滤 Media 来取得音频信息。

果然,在设置监听和过滤之后,再次点击播放按钮,我们就获得的一个请求音频资源的封包:

那么他的Request URL就是真正的下载地址了(打开后是一个播放框,右键另存为就好了),而我们也能通过Response包中的Content-type来判断出他是一个mp3格式的音乐。最后将下载得到的文件重命名并且加上.mp3后缀方便操作系统识别就好了。(当然也可以通过查看文件头来判断文件类型,见:利用文件头判断文件类型)

C99显示函数名的宏__func__

Posted on 2016-01-12 | In C/C++

前言

在调试代码或者写一些通用的测试函数的时候,有时候想如果能够用字符串的方式显示出正在调用的函数名该有多好。其实在C99标准中就已经有了这样的宏__func__,只是平常不怎么被提起。那么这个宏怎么用呢?

示例

程序:

1
2
3
4
5
6
7
8
#include<iostream>
using namespace std;
void fun(){
cout<<__func__<<endl;
}
int main(){
fun();
}

结果:

1
fun

没错,就是这么简单,非常方便。特别在某些调用函数指针进行测试的函数里,用这个东西来显示当前所调用的不同函数还是特别轻松的。比如:

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
29
30
31
32
#include<iostream>
using namespace std;
string insertionSort(int *a , int n){
//------
return string(__func__);
}
string bubbleSort(int *a , int n){
//------
return string(__func__);
}
string quickSort(int *a , int n){
//------
return string(__func__);
}
string mergeSort(int *a , int n){
//------
return string(__func__);
}

void test(void (*sort)(int *,int),int *a,int n){
int time;
//-----
cout<<(*sort)(a,n)<<time<<endl;
}
int main(){
int a[100];
//----
test(insertionSort,a,100);
test(bubbleSort,a,100);
test(quickSort,a,100);
test(mergeSort,a,100);
}

这就可以非常轻松的显示各个方法调用后运行的结果了,而不用手动写函数名了。

vim高级用法之ctags工具

Posted on 2016-01-11 | In Linux

都说vim强大,然而之前的简单用法并没有让我觉得vim有多强大,顶多是一个功能齐全的记事本,只到我发现了这个工具--ctags,以及由他衍生出来的很多插件,让我明白了,“哦,vim 至少可以作为一个很不错的C语言的IDE”。~~

概述

ctags工具其实可以认为是为C语言的文件添加索引的工具。C文件经过他的处理后会生成一个tags文件来保存文件中所有函数、变量、宏的索引,通过这个索引,就能非常方便的在后续的编辑过程中获取这些信息,从而达到自动补全、识别函数和变量等一系列的功能。

安装

ctags工具有他的官网可以下载,但是实际上我们并不需要手动安装。一般情况下ubuntu系统内会自带ctags工具,他的名字叫:exuberant-ctags(朝气蓬勃的C标签0.0)。可以通过$ ctags --version 命令来查看版本。如果没有,则只需要$ sudo apt-get install exuberant-ctags 就可以直接下载使用了。

使用

首先,对我们需要索引的文件进行预处理:$ctags foo.cpp(当然,如果需要递归处理所有子文件夹的话可以加 -R 参数,如: $ctags -R)。

预处理后,我们会发现在当前文件夹下出现了名叫tags的文件。比如,对于如下的cpp文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include<stdio.h>
struct FOO{

};
void fun(){

}
int global;
int main(){
fun();
FOO foo;
int local;
}

生成的tags文件是这样的:

1
2
3
4
5
6
7
8
9
10
!_TAG_FILE_FORMAT       2       /extended format; --format=1 will not append ;" to lines/
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
!_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/
!_TAG_PROGRAM_NAME Exuberant Ctags //
!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/
!_TAG_PROGRAM_VERSION 5.9~svn20110310 //
FOO a.cpp /^struct FOO{$/;" s file:
fun a.cpp /^void fun(){$/;" f
global a.cpp /^int global;$/;" v
main a.cpp /^int main(){$/;" f

大概解释一下他的文件格式就是:

1
2
3
4
5
6
7
8
格式:{tagname} {TAB} {tagfile} {TAB} {tagaddress} {term} {field} ..
• {tagname} - 标识符名字,例如函数名、类名、结构名、宏等。不能包含制表符。
• {tagfile} - 包含 {tagname} 的文件。它不能包含制表符。
• {tagaddress} - 可以定位到 {tagname}光标位置的 Ex 命令。通常只包含行号或搜索命令。出于安全的考虑,vim会限制其中某些命令的执行。
• {term} - 设为 ;" ,这是为了兼容Vi编辑器,使Vi忽略后面的{field}字段。
• {field} .. - 此字段可选,通常用于表示此{tagname}的类型是函数、类、宏或是其它。
!_TAG_FILE_SORTED<Tab>1<Tab>{anything}
上面这个标记说明tag文件是经过排序的,并且排序时区分了大小写,对排序的tag,vim会使用二分法来进行查找,大大加快了查找速度;如果值为0,则表示tag文件未经排序;如果值为2,则表示tag文件是忽略大小写排序的。

其实就是规定一种保存结构体、函数名、和全局变量的索引了。

经过这样的处理之后,我们就可以使用他带来的非常实用的操作了:

  1. 对于已经建立索引的条目,我们可以用Ctrl+] 的快捷键来快速找到他的声明,即使是位于不同文件(就像很多IDE中的F12用来查看声明一样),查看完之后可以通过Ctrl+t  或Ctrl+o 来返回原来的地方。
  2. 选中局部变量,按gd 可以搜索到该变量的声明。
  3. 选中单词,按*可以转到该单词下一次出现的地方。
  4. 选中单词,按#可以转到该单词上一次出现的地方。
  5. 在行末模式下输入:ta foo 可以立刻找到foo函数的声明。

注意

要使用tags文件,默认是必须要在当前含有tags文件的地方打开vim才能加载到tags文件,否则需要在行末模式下手动指定:set tags=(你存放tags文件的路径,如果有多个路径的话中间用,隔开,而且貌似不支持*之类的通配符) 或者在/etc/vim/vimrc里面加上这句话,或者在~/.vimrc 里面加上这句话。

晓得了这个工具,就像是打开了vim 插件类工具的大门,强大的 vim 配置就要诞生了。

保持SSH连接持续不断的配置方法

Posted on 2016-01-10 | In SSH

前言

在修改服务器的一些文件的过程中,经常碰到的情况就是需要隔一段时间修改一下文件,然后需要去查阅相关的资料,等下一次想修改的时候发现ssh连接由于长时间未相应已经断开了。而且这时候终端会卡在那里,十分的不方便。所以在网上找了几个配置SSH的方法,能保证连接能够长时间不断开。
方法有两种,一般配置一种就可以。但是我为了效果更好,把他们同时配置一下:

客户端

在/etc/ssh/ssh_config 配置文件中,将Host * 后面添加ServerAliveInterval 30  ,再保存即可。

那么这个条目哪来的呢?其实在他配置文件本身早就有这个的说明了。

打开配置文件/etc/ssh/ssh_config ,我们大概会看到这样的样子:

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
# This is the ssh client system-wide configuration file.  See
# ssh_config(5) for more information. This file provides defaults for
# users, and the values can be changed in per-user configuration files
# or on the command line.

# Configuration data is parsed as follows:
# 1\. command line options
# 2\. user-specific file
# 3\. system-wide file
# Any configuration value is only changed the first time it is set.
# Thus, host-specific definitions should be at the beginning of the
# configuration file, and defaults at the end.

# Site-wide defaults for some commonly used options. For a comprehensive
# list of available options, their meanings and defaults, please see the
# ssh_config(5) man page.

Host *
# ForwardAgent no
# ForwardX11 no
# ForwardX11Trusted yes
# RhostsRSAAuthentication no
# RSAAuthentication yes
# PasswordAuthentication yes
# HostbasedAuthentication no
。。。。。

注意到在最后有很多的注释掉的配置,很明显,这就是常用的可选条目。但是看了下并没有我们想配置的内容。

再仔细的看了下开头的说明,注意到有这样一句话:# ssh_config(5) man page. ,哦~,原来这个配置文件有man文档,OK,打开之后果然在当中找到了这样的配置:

1
2
3
4
5
6
7
8
9
10
ServerAliveInterval
Sets a timeout interval in seconds after which if no
data has been received from the server, ssh(1) will
send a message through the encrypted channel to request
a response from the server. The default is 0, indicat‐
ing that these messages will not be sent to the server,
or 300 if the BatchMode option is set. This option
applies to protocol version 2 only. ProtocolKeepAlives
and SetupTimeOut are Debian-specific compatibility
aliases for this option.

那么一切都清楚了~~~原理就是让客户端每隔一段时间向服务端发送信息来保持唤醒。

服务端

服务段的原理和客户端一样,只不过由于是服务器,所以配置文件不一样。服务端的配置文件是/etc/ssh/sshd_config 。查看man sshd_config ,我们可以看到这样两个配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
ClientAliveCountMax
Sets the number of client alive messages (see below)
which may be sent without sshd(8) receiving any mes‐
sages back from the client. If this threshold is
reached while client alive messages are being sent,
sshd will disconnect the client, terminating the ses‐
sion. It is important to note that the use of client
alive messages is very different from TCPKeepAlive
(below). The client alive messages are sent through
the encrypted channel and therefore will not be spoofa‐
ble. The TCP keepalive option enabled by TCPKeepAlive
is spoofable. The client alive mechanism is valuable
when the client or server depend on knowing when a con‐
nection has become inactive.

The default value is 3\. If ClientAliveInterval (see
below) is set to 15, and ClientAliveCountMax is left at
the default, unresponsive SSH clients will be discon‐
nected after approximately 45 seconds. This option
applies to protocol version 2 only.
1
2
3
4
5
6
7
ClientAliveInterval
Sets a timeout interval in seconds after which if no
data has been received from the client, sshd(8) will
send a message through the encrypted channel to request
a response from the client. The default is 0, indicat‐
ing that these messages will not be sent to the client.
This option applies to protocol version 2 only.

根据说明,添加如下两行即可:

1
2
ClientAliveInterval 60
ClientAliveCountMax 3

这样就可以保证连接始终唤醒了。

1…484950…58

574 posts
69 categories
286 tags
© 2024 Companyd
Powered by Hexo
|
Theme — NexT.Muse v5.1.4