用线上数据库做开发

我在开发Web网站的时候,一般在本地调试好没问题后,再上传到服务器。本地调试时,数据从哪里来呢?通常我会在刚开始的时候生成一些伪数据作为测试用途,如果是已经上线的系统,则我可能会dump一部分数据(通常一个月)下来,然后测试。然而,每次都这么做则要耗费不少时间,而且还要占据本地的存储空间。另外,如果换台机器开发,这个过程可能还要重复一次。

直到最近一次阅读中,发现ssh有-L这个参数,使得我可以把远程数据库当作本地数据库使用。具体来说,-L参数可以把发往本地端口的数据透明地传送到指定目标的指定端口。-L port:host:hostport,其中port是本地监听的端口,host是目标主机(从ssh服务器发起连接),hostport是目标主机的端口。因此,-L 3306:localhost:3306,就能把发往本地3306端口的数据转发到ssh服务器的3306端口,从而在本地可以直接访问MySQL服务器。

MySQL connection

值得注意的是,如果这时直接连接服务器,例如mysql -u root,那么会提示错误,如上图所示。这是因为,mysql如果发现服务器是localhost时,会自动使用socket file,而不是建立TCP连接。解决方法是让mysql客户端强制使用TCP连接,即加--protocol=TCP;或者指定host为127.0.0.1,即-h 127.0.0.1。

除了文中的例子外,端口转发还能做很多事情,大家不妨发散思维。值得注意的是,直接利用线上服务器做开发有一定风险,只涉及查询数据的开发我才敢这么做,如果涉及到修改数据,那还是用测试数据库吧。

发表在 Colorful Internet, Orange Software | Tagged , , | 发表评论

窗口过高的问题

一般情况下,如果某个应用程序的窗口过大,我们可以把鼠标放到窗口的四周,然后调整大小;或者右键单击标题栏,选择“改变大小”;或者直接把窗口最大化。但是,有某些应用程序会有最小高度(或最小长度),无论怎么改变窗口大小都不能比最小高度小,比如Android的模拟器。

Move Window

Gnome下可以通过“移动”窗口解决这个问题。首先,第一步可以通过右键单击标题栏,选择“移动”启用移动窗口,或者直接用快捷键Alt+F7也可以启用;第二步则用鼠标或键盘的方向键移动窗口的位置;最后单击或回车确定。上图中,是我把Android模拟器向上移动后的样子。

其他桌面环境应该也有类似的功能。遗憾的是,Windows XP的窗口移动后,如果超出屏幕范围,它又自动调整窗口的位置和大小,使之前的移动没有效果。

发表在 Orange Software | Tagged , | 发表评论

初学netcat

前几天,从网络中得知netcat这一被称为“网络瑞士军刀”的神器后,学习了一些基本的用法,现在总结一下。

使用netcat,我们可以把计算机A上的文件传到计算机B上。根据建立连接方式的不同,我们有两种方法。方法一,计算机B负责监听,A向B主动连接。这时在B上先输入“nc -l 8000 > file”,其中8000是监听的端口,然后在A上输入“nc IP 8000 < file”。方法二,计算机A负责监听,B向A主动连接。这时先在A上输入“nc -l 8080 < file”,然后在B上输入“nc IP 8080 > file”。

netcat从名字上是net+cat,但是它和cat有着本质上的不同。cat把标准输入的内容拷贝到标准输出,是单向的。然而,netcat是双向的,两台计算机的netcat建立连接后(不妨把两台计算机称为A和B),A从标准输入读到的东西,会经过网络,然后从B的标准输出出来,反之亦然。

netcat

我觉得这种I/O很像立交桥,它能同时处理两路I/O,然而,把netcat用于传文件显然只能用到其中一路I/O。如果能同时用上两路I/O,会发生什么有趣的事情呢?首先,如果两端的netcat的输入和输出都是接Terminal,那么两端的人可以用nc聊天,如上图所示。

如果把监听的一端(不妨称为计算机B)的输入输出重定向,那就更有趣。比如把B上nc的输出接到bash,然后把bash的输出又接回nc,那么B就是一个bash服务器,相当于开了个后门。具体实现可以使用命名管道和重定向,

mkfifo named_pipe; bash named_pipe | nc -l 8000 > named_pipe

同理,如果把程序换为cat,那么B就是一个echo服务器;如果把程序换为date,那么B就是一个date服务器。但和真正的服务器不一样,B只能接受一个连接,并且接受一次连接后就马上退出。

发表在 Blue Sysadmin | Tagged , , | 发表评论

制作自签名的证书

当搭建一个内部网站系统时,我们可能会使用自签名(self-signed)的证书,它的主要目的不是防伪,而是使用户和系统之间能够进行SSL通信,保证密码等个人信息传输时的安全。

一般情况下,制作证书要经过几个步骤,如上图所示。首先,用openssl genrsa生成一个私钥;然后,用openssl req生成一个签署请求;最后,把请求交给CA,CA签署后就成为该CA认证的证书了。

如果在第二步请求时加上-x509参数,那么就直接生成一个self-signed的证书,即自己充当CA认证自己。

除了这种方式外,在Debian或者Ubuntu系统中有更加简便的方法制作self-signed证书——使用make-ssl-cert(1)命令。该命令在ssl-cert的包里,一般会伴随着Apache的安装而安装,可能单独安装也可以。

make-ssl-cert generate-default-snakeoil命令生成一对万金油式的公钥密钥,可以直接使用。其中,公钥(证书)在/etc/ssl/certs/ssl-cert-snakeoil.pem,密钥在/etc/ssl/private/ssl-cert-snakeoil.key。另外make-ssl-cert还可以根据模板生成公钥密钥,并保存在其他位置,这样我们可以在默认的模板文件的基础上添加一些信息,如Organization等,默认的模板文件在/usr/share/ssl-cert/ssleay.cnf。例子:

# make-ssl-cert /usr/share/ssl-cert/sslsvn.cnf /home/svn/sslsvn.pem

我利用模板文件生成了一个公钥私钥文件,它们的内容放在了一起,一般问题不大,如果实在需要分开,手工分开即可。还有一点值得注意,我发现Debian里,make-ssl-cert是只能由root执行的命令。

使用这个方法,我们就可以快速方便地生成一个或多个公钥密钥对。

发表在 Blue Sysadmin | Tagged , | 发表评论

设定Ubuntu启动服务

当我们安装了一些Ubuntu的服务后,有时希望配置它为自动启动或不要自动启动。比如我最近安装了tor和privoxy,我希望设定它们不要自动启动。

怎样做呢?Ubuntu虽然是使用upstart进行启动,但是Ubuntu还是模拟了System V的运行级别体系。首先,服务脚本要出现在/etc/init.d/下面。然后/etc/rc0.d/到/etc/rc6.d/分别代表0到6的运行级别,每个级别对应的目录下面,有着刚才init.d目录里脚本的软链接,但是名字和原来不完全一样,Ubuntu启动的时候就是根据rcX.d/目录里软链的名字做出相应的动作。

比如我的Ubuntu 8.10默认是进入运行级别2的,如果rc2.d/目录下有S20tor软链接,表示启动的时候自动运行tor服务。软链接名字的第一个字符或者是S,或者是K,S表示start,K表示stop。接下来数字NN表示优先级,20是默认值,启动的时候先执行K开头的服务,在其中按NN从小到大执行,接下来执行S开头的服务,也是按NN从小到大执行。比如目录里有K50,K60,S10,S20,那么启动到该运行级别时按K50->K60->S10->S20的顺序执行。优先级的目的是提供服务的依赖性,比如A服务要依赖于B服务的运行,可以设置B为S20,A为S21,然后stop的时候要相反顺序。为什么先执行K呢?那是因为切换运行级别的时候,先关闭服务再开启的顺序不容易乱。

说了这么久,相信读者都明白配置Ubuntu启动服务是否自动运行可以直接编辑软连接的名字了。要自动运行,就是要在相应运行级别下加入S开头的软链接。如果不要自动运行,或者把链接删掉,或者设为K开头的名字。需要指出的是,把软链接删掉是不正确的方法,因为当软件包升级的时候,升级脚本运行update-rc.d命令,就会重新加入那个软链接,因此正确的方法是把S改为K,这样不会受update-rc.d命令影响。进一步要指出的是,我们最好也使用update-rc.d命令去进行软链接的操作。

典型用法一,把服务加到2,3,4,5级别自动运行,加到0,1,6自动停止。

sudo update-rc.d foobar defaults

或者

sudo update-rc.d foobar start 2 3 4 5 . stop 0 1 6 .

典型用法二,把服务设定为启动时自动停止。

sudo update-rc.d -f foobar remove
sudo update-rc.d foobar stop 0 1 2 3 4 5 6 .

值得注意的是,如果任意一个rcX.d/目录已经有某脚本的链接,必须像刚才的命令第一行一样先删除原来的链接,再进行添加。

发表在 Blue Sysadmin | Tagged , , | 2条评论

HTML5乒乓球

Solidot介绍,pong是一个用HTML5和javascript编写的乒乓球游戏,我试了一下,Ubuntu 9.10下的Firefox 3.5及8.10下的3.0都能玩,玩的时候要允许网站弹出窗口。

pong

正如游戏的提示,按下p后,游戏就开始。首先会弹出三个窗口,左右两个表示player,中间那个表示球。用户只要按上下键控制player移动就可以了。比赛是11分制的,pong可以适当打发时间,如果刚好有两人,也可以对战。

发表在 Colorful Internet | Tagged | 发表评论

Happy New Year

昨晚在北京路划算地买到了喜欢的鞋,然后看着东方卫视播林俊杰,郭富城和黎明,倒数2010的新年!

uname2_6_27_16

新的一年,我的Ubuntu 8.10系统也换了两个新的引擎,内核升级为2.6.27-16,nvidia显卡驱程升级到195,现在用mplayer看高清,可以直接用显卡硬解了。

最后,在新的一年里祝愿大家心想事成,新年快乐!

发表在 Green Diary | Tagged , | 发表评论

比左边和上边大的矩阵

昨天遇到一道矩阵的题目。这个矩阵有一个特性,对于任意元素,所有它左边和上边的元素都比它小,或者用形式化的语言来说,任意(x,y),凡是i小于等于x和j小于等于y,且(i,j)不是(x,y),那么(i,j)小于(x,y)。

 1  4  5  8  9
 2  6  7 11 13
 3 10 18 19 20
12 15 21 24 28
14 16 22 25 29

上面给出了一个符合要求的例子,题目问如何查找一个元素是否在矩阵中。

我第一个想法是从左上角开始,先在对角线上找。当要找的值介于两个对角元素之间时,再横着找或竖着找。比如要找7,先是1,往对角线6,然后18,这时6小于7,7小于18,再竖着找。但是其实这种方法是错误的,比如我们要找15,首先也是找到6和18之间,但是之后无论横着找还是竖着找,都找不到15,但15是在矩阵里的。这种方法不行是因为虽然题目说任意元素左边和上边元素比它小,但是并不是比它小的元素都在它左边和上边。

我第二个想法是逐行搜索(或者逐列搜索),因为每一行本身是有序的,所以可以用二分法去搜。这种方法是行得通的,于是我就没有再想下去了。后来请教同学,发现有一种更简单的方法,我估计那就是题目想要的正解。

方法是这样的,从右上角开始。如果元素的值比目标值大,那么说明元素所在的列都比目标值大,所以整列都不用考虑,因此往左移动一格;同样道理,如果元素的值比目标值小,那么元素所在的行都比目标值小,这时应该往下移动一行。这样,算法最坏的复杂度不超过O(m+n),m和n是矩阵的宽度和高度。下面我用C实现了一下。

// val - the value searched
// matrix - the matrix we want to find val
// row - number of rows in matrix
// col - number of columns in matrix
// return 1 if found
// return 0 if not found
int matrixFind(const int val, const int *matrix, const int row, const int col)
{
	int i = 0;
	int j = col - 1;

	while (i < row && j >= 0) {
		int cur = matrix[row * i + j];
		if (cur == val)
			return 1;
		else if (cur > val)
			j--;
		else
			i++;
	}
	return 0;
}

我觉得最后一种解法的巧妙之处在于突破了惯性思维,因为一般情况我们都从左上角想起,但是这个算法从右上角开始,当然,从左下角开始也是可以的。

发表在 White Programming | Tagged , | 发表评论

Tracert与Traceroute

traceroute是一个检查网络路径的工具,最初由Van Jacobson实现。它现在已经成为Linux、Cisco IOS以及其他很多操作系统的基本网络工具之一,Windows下也有一个类似的工具tracert。下图是Linux执行traceroute的结果,它能显示每一跳的IP地址及域名(如果反向查询成功),以及对应的往返时间。

traceroute3

traceroute与tracert的原理是很类似的,它们通过设置IP报文里的TTL字段,TTL在每个路由器里都会减1,因此到了指定的跳数之后,TTL刚好减到0。如果这时候还没到达目的地,那么路由器会返回一个类型11的ICMP报文,表示time exceeded(TTL为0)。从而,原主机根据这个ICMP报文就能知道每一跳的IP地址。

但是,其实traceroute具体的实现方法与tracert是不同的,我昨晚在Packet Tracer做了下面的实现。首先看看实验的拓扑图,我做了两次实验,第一次从laptop2a使用tracert,目的地是dhcp(IP地址是8.8.8.2);第二次从core2使用traceroute,目的地同样是dhcp。我的目的是观察到tracert与traceroute的不同。

sample-topology

tracert1

从上图可以看到,tracert使用的ICMP类型8报文,即ICMP Echo Request,与ping程序一样。可以看到,第一次TTL设为了1,可以预见这个报文将会在core2丢弃,并返回ICMP Time Exceeded报文。下图是返回的报文,可以见到ICMP报文里还会附上原来报文的内容。根据《TCP/IP详解》的说明,ICMP的差错报文需要附上原来报文的IP报头,以及后面紧跟着的8个字节,不过现在的实现一般都把更多的字节附上。

tracert2

为什么必须多8个字节呢?因为这样做可以把ICMP Echo Request报文里的标识符字段和序列号字段包含进来,那么如果原来客户端同时开了两个tracert程序,客户端可以根据标识符字段区分交给哪个进程处理。实际上,TCP/IP协议栈就是故意这样设计的,IP报头后面的ICMP报头,或者UDP报头,或者TCP报头,它们的前8个字节就已经包含了端口号、序列号等所有能区分进程的信息,从而ICMP差错报文会把这些信息附上。

对于tracert来说,如果TTL大到可以到达目的地,那么目的地会返回一个ICMP Echo Reply(ICMP报文类型0),就像ping一样。这时,tracert就可以结束了。

traceroute则不一样,它不是使用ICMP Echo Request报文,从下图可以看出,它是使用UDP报文。UDP的源端口用于标识主机上不同的traceroute程序,原理刚才已经分析过了。目的端口从33434开始,每一个报文会把目的端口增加1,直到33534,目的是为了区分返回的报文对应哪个发出的报文。

traceroute1

traceroute2

如果TTL不足以去到目的地,就和tracert的情况一样,路由器返回一个ICMP Time Exceeded报文。那么如果到达目的地会发生什么事呢?上图里有了答案,目的地返回一个类型3,代码也是3的ICMP报文,表示端口不可达。所以,我们还可以知道多一个常识,即主机的33434到33534端口一般不能作为服务用途的,因为traceroute希望目的地返回端口不可达。traceroute收到这个报文之后,就知道已经到达目的地,可以结束程序了。

总结一下,tracert是使用ICMP Echo Request报文去实现,traceroute是使用UDP报文去实现,不过基本原理都是利用IP报文的TTL字段。现在的互联网复杂很多,有些路由器屏蔽了其中一种检查路径的方式(甚至两种都屏蔽),所以同时使用tracert和traceroute,再把结果合并,有时会更好。因此,traceroute实际上更有优势,因为现代版的traceroute只要加-I选项就相当于tracert的功能。据说现在还有一种使用-P选项的方式使用TCP报文的,但是我还没试过。

发表在 Black Study | Tagged , , | 1条评论

Ubuntu下使用Packet Tracer

我目前还是使用Ubuntu 8.10系统,Packet Tracer使用的是最新的5.2.1版本。

最新版的PT和以往一样,对Windows,Linux和Mac OS X都提供支持,估计主要原因是使用了Qt4编写的GUI。问题是PT针对Ubuntu的版本,字体显示很是难看(有锯齿),而新版甚至出现输入框输入IP地址时,显示不出来或者只显示部分的问题。

上网查找了一番,原来原因在于PT是用自带Qt库,而这个Qt库可能版本较旧或者存在缺陷。因此解决方法就是不使用PT自带的Qt库,转而使用系统自身的Qt库。对于Ubuntu,首先找到路径/usr/local/PacketTracer5,用编辑器打开packettracer脚本,把其中的指定库路径的LD_LIBRARY_PATH注释掉即可。第二步,系统需要安装部分Qt4的运行库,具体要安装哪些,可以参考里面的lib目录,运行库在Ubuntu里的package名字都是以libqt4开头的,具体名字用apt-cache搜索一下,比如Qt4的XML支持在Ubuntu下的安装,

sudo apt-get install libqt4-xml

其他Qt4的运行库也可以用类似的方法安装。

PT

这样就大功告成了,运行的时候字体和系统的一致了,而且估计Ubuntu下的System菜单配置中全局的Qt4配置也会对PT起作用。完成了之后,就可以愉悦地在Ubuntu上学习CCNA或者其他思科技术了。

发表在 Orange Software | Tagged , | 发表评论