存档

2010年8月 的存档

linux0.11里面发现的好玩的链表指针迭代方法

八月 30th, {2010 2 条评论 7,329 人阅读过  

linux的内存管理一直是让我最困惑的,2.6版本内核里面各种复杂的机制搞得我云里雾里,甚至搞不明白内存管理最基本的原理是什么,于是翻阅早期版本的内核0.11,最底层的内存分段和分页我都已经在我的plinux上实践过了,读到malloc的时候发现了linus用了一种很好玩的指针迭代方法,至少我以前没见过,见识短浅,大家莫笑。

linus把一页内存分成一个个具有相同大小的内存块,然后又将这些个内存块组成一个链表,而这些内存块都是将来要分配出来的空闲内存,它们内部并不包含有任何对象,要组成链表就必然要求有指针,linus把每块内存的前4个字节拿出来作为指针,指向下一块内存的首地址:

char  *cp;
/* 在这里获取一页空闲内存 */
(void*)cp = get_free_page();
 
for(i = PAGE_SIZE/bdir->size; i > 1; i --){
/* 我觉得这里很有意思,把一个字符指针强制转换成指向字符指针的指针,
然后再对其解引用赋值,相当于把cp开始的前4个字节作为一个指针并对它进行定向 */
    *((char**)cp) = cp + bdir->size;
    cp += bdir->size;
}

然后在指针迭代的时候用了下面这种方法,不复杂,只是觉得挺有意思的:

void *retval = (void*)freeptr;
freeptr = *((void**)retval);

这样freeptr就指向了下一块空闲内存。

分类: C/C++ 标签: ,

统计使用频率最高的10条指令的脚本

八月 22nd, {2010 5 条评论 8,584 人阅读过  

说实话,自己脚本能力太差了,于是利用周末的时候读了读《sed&Awk》,记得什么时候在byr上看到一贴子,是个统计最常用的10个命令的一句话脚本,于是自己写了一个,不过看上去挺臃肿的,如下:

#! /bin/sh
 
cat ~/.bash_history | awk -F" +" '{ print $1 }' | sort  | awk '
!/^$/{
	if(cur != $1) {
		if(cur != "")
				print sum , cur
	   	sum =0
	}
	cur = $1
	sum ++
}' | sort -nr | awk '
BEGIN{
printf("%-20s%s\n" , "Command" , "Frequency")
print "-------------------------------"
}
{
	if(NR <= 10)
		printf("%-20s%d\n" , $2 , $1)
}'

输出如下:

Command             Frequency
-------------------------------
make                65
ls                  49
awk                 49
cd                  42
sed                 31
gvim                25
sudo                23
cat                 19
echo                17
man                 11

分类: Linux 标签: ,

slackware13.1安装配置手记

八月 17th, {2010 9 条评论 10,421 人阅读过  

近日实验室一台thinkpad挂在我名下,为了防止资源的闲置浪费我决定拿过来用一段时间,正好也是项目需要,之前的程序需要gnome NetworkManager的支持,我前一段不得已时间在slackware13.0上将xfce换成了gnome,然后又装NetworkManager,后来还是没有成功,装是装好了,可 dbus仍有问题,程序跑不起来,不得已用了在这台机器上装了个ubuntu用了几天,现在项目中期已过,差不多该回过头来整理一下操作系统了,还是钟爱于slackware,而且早就想试一下13.1,正好借这个机会尝试一下。

从slackware官网上下了前两个cd,把vmlinz和initrd.gz解压出来放到了ubuntu的某个目录下,然后把第一个cd解压出来或者在安装的时候临时挂载也行,我是解压出来了,然后就是硬盘安装的各种熟悉的步骤了,只不过这次的grub是ubuntu的grub2,有一点不一样,在加载内核文件的时候需要用linux命令,而不是kernel命令,其它的都一样,之前在安装系统的时候分区用的是cfdisk,这次联想把这个分区表弄得很乱,cfdisk打不开,于是用fdisk分区,其实我已经划好了一块分区准备留给slackware的,只要用mkfs格式化成ext3或者ext4就可以了,格式化完之后还不行,slackware还是检测不到linux分区,需要修改分区的system id:

1
sudo fdisk /dev/sda

然后选择t将分区的system id修改为83,也就是linux分区,w写进分区表就可以啦,fdisk就会显示分区是Linux,而不是FAT12了,这样就可以进行系统安装了,setup就可以了,其它的就没什么特别的了。

这次在系统安装的时候我只安装了cd1,cd2是系统安装完成之后手动安装的,里面有linux source和一些常用的软件还有xorg,这次没有安装xfce,xfce已经让我审美疲劳了,而且这台机器配置也不错,装gnome也不会慢多少,接下来就要安装gnome了。

其实slackware的包管理工具也是很出色的,有slackpkg和slapt-get可以用,而且也都很不错,只不过在国内都找不到它们可用的源,能用的只有官方提供的源,而且都放在国外,教育网要用的话只能加代理,用起来有点麻烦,我比较喜欢slap-get,首先到gsb(Gnome Slackbuild)上下载slapt-get安装,更新一下配置文件

1
sudo vim /etc/slapt-get/slapt-getrc

我把所有的源都注释掉了,只用了下面的一个:

SOURCE=http://get.gnomeslackbuild.org/gsb/gsb-2.30_slackware-13.1/:PREFERRED

然后更新一下源:

1
sudo slapt-get --update

获取密钥:

1
sudo slapt-get --add-keys

在教育网内这些操作之前需要设置代理的环境变量

1
export http_proxy=http://username:password@proxy.bupt.edu.cn:8080

教育网就这点让人不爽,我边githug,sourceforge的svn都用不了。

更新一下系统:

1
sudo slapt-get --upgrade

更新完之后会有一个神奇的现象,我在环境变量里面设置代理貌似对slapt-get就不好用了,每次用slapt-get的时候需要为每条命令都设置代理环境变量才行,如下:

1
sudo http_proxy=http://username:password@proxy.bupt.edu.cn:8080 slapt-get --install gsb-desktop

不知道是什么原因,有懂行的帮忙解释下。

另外上面那条命令就是安装gnome的命令,大约过个十几二十分钟就装完了。

系统的汉化应该没什么问题,不像ubuntu那样还要去下载语言包,slackware已经集成了中文包,只要在/etc/profile.d/lang.sh里面改一下locale的环境变量就可以了。

1
2
3
export LANG=zh_CN
export LC_CTYPE=zh_CN.UTF-8
export LC_TIME=zh_CN.UTF-8

另外这里还要提一下ubuntu的locale设置,它貌似默认的设置都是zh_CN.ut8,其实locale对大小写是敏感的,如果是utf8的话大部分功能都没问题,就是gvim会出问题,各种报错和菜单的中文不显示等问题,最好还是改成zh_CN.UTF-8

OK,汉化也没问题了,重启一下就是中文的了,而且gnome也不会乱码。至于怎么装gdm怎么设置启动的运行级别以前写的一篇安装手记里面貌似都提过了,也很简单,没什么好说的了。

输入法还是小企鹅用得最顺手,去他们官网上下了个最新版的,好像是今天2月份才发布的版本,很不错,界面现在很漂亮,不像以前那些版本那么老土,不过这几天 fcitx经常自己消失了,不知道是不是有什么bug,也可能是我设置的有问题,不过影响不大。

gnome还是很强大的,既然用它就要把它的功能都利用起来,gnome的自动挂载那个功能是用起来最方便的,也不用自己再费劲去改fstab了,但slackware默认情况下是不好用的。

点击分区符的时候报下面的错误:

Cannot mount volume

Error org.freedesktop.DBus.Error.AccessDenied.

这个错误搭眼一看就知道是dbus的问题,幸亏之前耕宇的代码用到了dbus,我也跟着对dbus的原理有了点简单的了解,不过看这错误的命名规则跟java挺像的,不知道它底层是不是用java实现的,谁知道的。

不管怎么说,错误很明显地告诉我这是权限的问题,找了一顿在/etc/dbus-1/system.d/hal.conf里面找到了关于Volume和Storage的相关配置内容。

里面有这样一段话:

<policy group=”plugdev”>
<allow send_destination=”org.freedesktop.Hal”
send_interface=”org.freedesktop.Hal.Device.Storage”/>
<allow send_destination=”org.freedesktop.Hal”
send_interface=”org.freedesktop.Hal.Device.Storage.Removable”/>
<allow send_destination=”org.freedesktop.Hal”
send_interface=”org.freedesktop.Hal.Device.Volume”/>
<allow send_destination=”org.freedesktop.Hal”
send_interface=”org.freedesktop.Hal.Device.Volume.Crypto”/>
</policy>

很显然,只有在plugdev分组里面的用户才有这些权限,这个简单,把用户添加到这个分组里面就可以了,用户是可以属于多个分组的,用下面命令:

1
sudo usermod -G plugdev,audio levin

如果用户要属于多个分组的话就必须将多个分组用逗号隔开,否则用户就只会被添加到一个分组里面去,即只属于那一个分组了。

当然也可以修改/etc/group文件,之后最好再运行一下grpck命令更新一下gshadow文件。

这样就应该就没问题了,再点击分区符就可以成功挂载分区了。另外我上面把用户也添加到audio分组里面了,因为我新创建的用户不属于audio组,导致我的系统没有声音,这个很悲剧,alsaconf配置一下声卡就可以了。

对于挂载的另一种解决方案就是添加一段跟上面的xml相同的话,把groups改成当前用户的分组,那样也可以,我是那么干的。

最烦人的问题是 NetworkManager,我之前都不用的,现在因为项目程序里面用到了,最好还是装上,要不然这台机器就只能用来干私活了。

其实gsb为slackware13.1做的gnome里面已经集成了NetworkManager,但是默认的是跑不起来的, NetworkManager也用了dbus,用刚才的办法去找它的配置文件,修改分组也好,修改配置文件也行。

然后把/etc/rc.d/rc.networkmanager这个脚本的可执行权限给加上。

这样NetworkManager虽然能用了,但还是不能开机启动,关健的方法我自己没琢磨出来,到网上找到的解决方案:

在/etc/NetworkManager/nm-system-settings.conf这个文件里面添加下面这一句话就可以让NetworkManager开机自动启动。

managed=true

另外,还需要NetworkManager的托盘图标,就是nm-applet,把它直接在“启动应用程序”里面添加上就可以让它自动启动了。

一个神奇的问题是,开机后虽然NetworkManager启动了,而且也显示连接成功了,可ifconfig里面的eth0就是没有地址,系统安装完成之后我用

1
sudo netconfig

配置网络为dhcp方式自动获取地址,而且在启动的过程中它也确实显示成功获取到了地址,但开机这后就是没有地址。

而且我用

1
sudo dhclient eth0

获取地址之后,过个2s之后地址又没了,我都晕了,然后我尝试一下用下而把方法把网络停止:

1
sudo /etc/rc.d/rc.inet1 stop

之后再用dhclient获取地址,或者用NetworkManager获取地址都可以,能够正常上网,但这种情况下我的firefox时面菜单弹出相当迟钝,而且还有更神奇的问题是我的gvim里面会有闪铄,这都是些什么问题,我也不清楚slackware自己的网络配置和NetworkManager到底有什么冲突,反正后来我无耐之下用netconfig 把网络地址设成loopback,之后再重启让NetworkManager获取地址就OK了,问题是解决了,但还是觉得挺神奇的,不知道NetworkManager都干了些什么。

其它的就没什么问题了,换了我长期使用的主题T-ish,图标主题是从gsb的源里面找到的一个,感觉不错,也用了很久,叫Neu,在gnome-look上没找到。

删掉了slackware安装cd里面带的firefox3.6.3,安装了3.6.8中文版。

字体以前是用Vera Sans YuanTi,后来用了几天的ubuntu,发现其实微软雅黑看上去确实挺漂亮的,也装了一下,挺舒服的。其它的就没什么特别的了,我也几乎不需要什么娱乐,有个smplayer能看个电影就行,把所有的音乐播放器都删了,电脑上一首歌也没有,都是在线听的,另外有个Adobe Reader和Vim就够了。

分类: Linux 标签: ,

近期飞信开发手记(群相关介绍)

八月 14th, {2010 22 条评论 11,394 人阅读过  

实验室项目中期检查结束,两天一夜的超负载工作换来了额外两天的休息时间,时间不敢随意浪费,飞信好久没有更新了,软件总不可能没有bug,用户的需求也不可能有止境,还是得赶紧把这么长时间以来网友提出的问题和要求给解决一下,用了近三天的时间完成了飞信i18n和飞信群功能,宅在宿舍里面写代码时间长了果然会觉得无聊,闲话少说,切入正题,写一下飞信群的开发过程。

另外,现在还不打算发布新版本,还想再测试两天看看,这里就截两个图先展示一下吧

image image

其实飞信群这个功能本来也没几个人在用,分析了一下协议,没有什么特别复杂的地方,很多东西都是套路,首先是在登录的时候获取一系统群相关的信息,如群列表,群成员列表,群详细信息,群个人信息,推荐群,群话题等等,一些没用的信息像推荐群,群话题这些在windows下都不会有人去点的信息就直接给忽略了,登录的过程中发送一系统的获取信息的信令,然后再统一根据 callid从服务器返回的信息中提取各自相关的信息,获取群列表信令如下:

S fetion.com.cn SIP-C/4.0
F: ×××××××××
I: 3
Q: 1 S
N: PGGetGroupList
L: 27

<args><group-list /></args>

获取群详细信息信令如下:

S fetion.com.cn SIP-C/4.0
F: ×××××××××
I: 5
Q: 1 S
N: PGGetGroupInfo
L: 150

<args><groups attributes=”all”><group uri=”sip:PG9777218@fetion.com.cn;p=12205″ /><group uri=”sip:PG31809932@fetion.com.cn;p=12207″ /></groups></args>

获取群成员列表信令如下:

S fetion.com.cn SIP-C/4.0
F: ×××××××××
I: 12
Q: 1 S
N: PGGetGroupMembers
L: 229

<args><groups attributes=”member-uri;member-nickname;member-iicnickname;member-identity;member-t6svcid”><group uri=”sip:PG9777218@fetion.com.cn;p=12205″ member-list-major-version=”" member-list-minor-version=”" /></groups></args>

这些信息发送至服务器这后,服务器会将相关的请求信息推送过来,程序编写时在发送每一条信令都记住其相关的callid,再根据返回信息中的callid来判断其是什么信息,然后再将其解析。

这些信息获取之后就需要订阅每个群的Presence信息,信令如下:

SUB fetion.com.cn SIP-C/4.0
F: ×××××××××
I: 2
Q: 2 SUB
N: PGPresence
L: 215

<args><subscription><groups><group uri=”sip:PG9777218@fetion.com.cn;p=12205″ /></groups><presence><basic attributes=”all” /><member attributes=”all” /><management attributes=”all” /></presence></subscription></args>

之后服务器会将群成员的Presence信息推送过来,信令格式大致如下:

BN 916098834 SIP-C/4.0
N: PresenceV4
I: 1
L: 159
Q: 55 BN
<events><event type=”PresenceChanged”><contacts><c id=”464933706″><pr di=”PCCL030524118392″ b=”400″ d=”" dt=”PC” dc=”137″></pr></c></contacts></event></events>

至此,群相关的信息都已经获取到了,已经可以在界面上展示飞信群了,但要发送群信息还不够,必须还要发起群会话邀请,也就是向sip服务器发送Invite信令,格式如下:

I fetion.com.cn SIP-C/4.0
F: ×××××××××
I: 10
Q: 1 I
T: sip:PG31809932@fetion.com.cn;p=12207
K: text/html-fragment
K: multiparty
K: nudge
K: share-background
K: fetion-show
L: 21

s=session m=message

服务器返回100 trying,之后返回200 OK,收到OK之后再向服务器发送Ack信令:

A fetion.com.cn SIP-C/4.0
F: ×××××××××
I: 9
Q: 1 A
T: sip:PG9777218@fetion.com.cn;p=12205

这样会话邀请就已经完成了,可以发送群信息了。但在这之后我发送群信息的时候却出了一点小问题,每次发送到服务器的Message信息格式完全正确,但服务器返回的是请求失败的信令,想了好久才想明白,其实发起会话邀请这一步并不是做给服务器看的,而是要通过它来注册一个callid,Invite信令的callid必须与Message信令的callid一致,消息才能发送成功,这表示发送的群消息是属于这个会话的,而标识正是在发起邀请时所用的callid,群消息发送的信令如下:

M fetion.com.cn SIP-C/4.0
F: ×××××××××
I: 9
Q: 2 M
T: sip:PG31809932@fetion.com.cn;p=12207
C: text/html-fragment
K: SaveHistory
L: 60

<Font Face=” Color=’-16777216′ Size=’10′>hello</Font>

然后就是群短信:

M fetion.com.cn SIP-C/4.0
F: ×××××××××
I: 25
Q: 1 M
T: sip:PG31809932@fetion.com.cn;p=12207
N: PGSendCatSMS
L: 12

hello fetion

群短信这里的callid就无所谓啦,可以让它使用递增的全局变量,当然也只有群的超级管理员才可以发送群短信,连管理员也不能发,所以我觉得这个功能限制也太多啦。

其实关于飞信群做的事情也就这些,像其它的一些邀请好友加入群,群管理之类的功能我都没做,本来就没有几个人在用这个功能,而且linux下用的就更少了,而且我也确实拿不出再多的时间去整了,就先把基本功能都弄好了让过来提示需求的网友先凑合着吧,如果将来飞信群用的人多了我再想办法后时间来完善它。

另外,我弄这个群比飞信的官方软件里面的群帅的地方就是群成员可以显示头像,当然啦,这些也都是浮云。