善意提醒

如果您打开本站很慢,布局排版混乱,并且看不到图片,那么可能是因为您还没有掌握用科学的方法上网的本领。

2006-08-28

C随机函数的正确用法

看到有同事在用rand() % 100 + 1这样的方法试图获取一个1~100的随机数。虽然rand()出来的确实是一个整数,而且确实会大于100,但是这样得到的随机数并不是从1~100机率均等的。用在某些场合,不是很合适。

在C中正确的取随机数应该是这样:

#include <time.h>
#include <stdlib.h>

// 初始化随机数序列
void randomize(void);
{
    srand((unsigned)time(NULL));
    return;
}

// 获得一个0<=x<1之间的随机数(双精度)
double randf(void)
{
    return (double)(rand()) / (RAND_MAX + 1);
}

// 获得一个0<=x<number之间的随机数(整数)
int random(int number)
{
    return (int)(rand() * number / (RAND_MAX + 1) );
}

random之前别忘了先用randomize进行初始化,否则每次出来的随机序列可是一样的。呵呵,用时间值进行初始化也不一定保险,特别是用在博彩系统中,曾有人根据系统启动时间推算出随机数种子的例子。有必要的话,建议各位加上别的因素(比如对鼠标进行采样等)进行随机数种子的初始化工作。


更新于18年以后:

后来有人跟我杠,说rand() % 100 + 1这样写才是对的。
我的确也在很多地方看到有人这样写,甚至包括V2EX。我有点不是很明白,现在程序员的门槛这么低了吗?这些人是不是都是写Web前端的?这已经不是编程问题了,这是数学不及格啊!
往轻了说,你为了性能和开发效率,在业务需求允许的情况下走了「捷径」,起码在心中要有这个X数,而不是来跟我杠说这个写法才是对的。你那么爱杠,去跟AI杠一杠吧,它会让着你的。

2006-08-24

Linux上FTP客户端实现自动登录

这是在制作服务器虚拟主机自动备份脚本的时候遇到的一个小插曲。

原本想使用输入重定向简单实现FTP客户端自动登录的,因此制作了一个文本文件进行实验:

a.txt

open www.某某.com
aaa
bbb
ls
exit

其中,aaa和bbb分别是FTP的用户名和密码。没想到在ftp < a.txt的时候,仍然让我输密码。看来输入密码的地方无法使用输入重定向来实现,得考虑另外的办法了。

翻阅ftp命令的在线帮助,发现它有auto-login功能。办法是在本用户(本例中是root)的用户根目录(如本例中root用户就是/root)下建立一个名为.netrc的文件,注意这个.可不能省。然后,在它里面存放一张FTP帐户列表,简单格式如:

machine www.某某.com login aaa password bbb
……(可以多行)

然后再直接ftp www.某某.com,就会发现ftp客户端直接以.netrc中设定的aaa用户名和bbb密码进行登录了。当然,系统在使用这张自动登录列表的时候,会根据FTP站点的名称进行核对的。如果没有发现指定的站点名,那么也不会应用这个自动登录功能的。

服务器虚拟主机自动备份功能

自己写了个脚本,来实现对我服务器上PHP+MySQL虚拟主机的自动备份。虽然目前只有我一个人在使用,但是即使这样,我也不希望数据因为意外事故损坏掉。

备份的原理,就是把Apache和MySQL先停掉,然后用tar打包HTML目录和MySQL的数据库目录,恢复MySQL和Apache服务之后,再慢慢通过FTP客户端传到我的一台远程FTP服务器上(其实是我在网上买的一个虚拟主机空间)。

备份周期完全由自己决定,我目前把它丢在/etc/cron.weekly下面让它每周运行一次。备份的文件会以备份日期自动命名。以后等我有了比较大的FTP空间之后,我就设置为按日备份。再在自己工作站上做一个按周归档,那就万无一失了。

脚本文件如下(隐去部分敏感信息):

#!/bin/sh
HOME=/root
# Stop the services
/etc/init.d/httpd stop
/etc/init.d/mysqld stop
# Tar the html bag
cd /var/www
tar -czf /tmp/html.tar.gz html
# Tar the mysql/data bag
cd /usr/local/mysql
tar -czf /tmp/mysql_data.tar.gz data
# Start the services
/etc/init.d/mysqld start
/etc/init.d/httpd start
# Build the ftp script
DATESTRING=$(date +%Y%m%d)
echo "open www.某某.com" > /tmp/ftp_$DATESTRING.txt
echo "put /tmp/html.tar.gz /wwwroot/vhostdatabackup/html_$DATESTRING.tar.gz" >> /tmp/ftp_$DATESTRING.txt
echo "put /tmp/mysql_data.tar.gz /wwwroot/vhostdatabackup/mysql_data_$DATESTRING.tar.gz" >> /tmp/ftp_$DATESTRING.txt
echo "exit" >> /tmp/ftp_$DATESTRING.txt
# Connect the backup FTP site and upload these files
ftp < /tmp/ftp_$DATESTRING.txt
# Clean temp files
rm -f /tmp/ftp_$DATESTRING.txt
rm -f /tmp/html.tar.gz
rm -f /tmp/mysql_data.tar.gz

增补于2006-09-10
如果想在cron中运行,在脚本中FTP登录之前还要加上HOME=/root,否则无法实现自动登录。原因……是crond运行脚本时的环境变量太过“干净”了。

2006-08-16

《铁甲威龙》观后感

很久以前就看过这片子了,改编的FC游戏也通关了很久了,还曾经制作成了录像。但是这些天突然又老夫聊发少年狂,一口气下了铁甲威龙系列的所有片子。慢慢观赏,又重新找回了那种曾经有过的感觉。

墨菲是一名青年警官,而且确实是金发碧眼——不过和某些文字的描述有所差别的是,他有老婆有孩子,男孩还不小了,所以虽然样子看起来还算年轻,但应该算是35左右的准中年了吧。他长得也算不上英俊,不过变成RoboCop,戴上头盔只露出下半张脸之后,却不知怎么的变得非常帅。我这才知道演员为什么会选他而不选别的小生。
墨菲耍枪的动作很酷,比某些国产片强多了。曾经看过一部国产片,警察拿手枪射驾车逃窜的匪徒,打了几枪居然是把手一松让枪往后转。还曾有一个穿警服的MM,转枪用了三个指头,花了三秒钟,丢脸哦!RoboCop耍枪也很酷,而且枪的托架从大腿中伸出,动作真是酷毙了!当年我也想在大腿上安一个枪架来着。
墨菲变成RoboCop之后,有一段时间致力于维护公共安全。记得印象最深的,就是那透过裙子的跨下一枪。很解气啊,解除了那男人犯罪的根源。我看已经不需要把他抓走了。
很快地,他的记忆复苏了。毕竟他的大脑、小脑等神经中枢都还在。他回忆起了自己被杀的情景。按理来说,作为RoboCop是不应该公报私仇的。但是,妻离子散,家破人亡,这使得他自行出动解决仇人。不过他最大的失误就是没有一枪把那个匪徒头子给打死,否则他的搭档后来就不会受伤了。
OCP的自保措施——RoboCop不能对OCP高级雇员下手,使得后台Boss逃过一劫。我疑心安置这种自保的Rule应该是OCP的习惯之一,因为负责RoboCop这个项目的人可是该后台Boss的死对头,他没理由让这个家伙知道这些的。可惜那可怜的ED209不是设计用来城市作战的,于是在楼梯间扭了脚。
接下来避难废弃工厂内。路易丝帮墨菲校正瞄准系统的那一幕真的很温馨,同时RoboCop也终于取下了面罩露出了他的真正面目。我现在还是想不通那画面效果是怎么拍出来的?头盔的话,似乎难度高了点。
那桶有毒废料不知道是什么东西,把一个匪徒变成了怪物。然后他又被车子撞成肉酱,真是可怜,看来连骨头都酥掉了。总之,可怜的匪徒,就算有火箭枪,也只是给墨菲送装备去而已。
接下来就轮到Boss了。那个场景在电影和游戏中同样经典。老板的一句「You are fired!」,接着就是那RoboCop专用枪的强大火力在身上打出的四个洞,然后就是摔窗而出。OCP的人似乎蛮喜欢从楼上飞下去的感觉……

本集中RoboCop不是受损最重的,但是在外表上是被打得最惨的。胸甲全烂了,一度用手护着脸暴露在N支轻火力之下。我在想,当时的警察如果装备的不是9mm的MP5,而是用的.50重机枪,说不定连机体都给打成筛子了。