存档

‘Linux’ 分类的存档

VIM复制粘贴的那些事

九月 7th, {2011 11 条评论 16,449 人阅读过  

说起vim的复制粘贴一直是个比较困扰我的问题,之前一直用gvim,跟系统剪贴板之间的复制粘贴都没有问题,gvim毕竟还需要再开个窗口,麻烦,而且不如vim那样快捷,但vim里面最让我头痛的是复制粘贴问题,想把vim里面的内容复制到其它的地方貌似怎么也不行,粘贴进来的话免强可以,但格式可能会很乱,折腾来折腾去,今天先是发现了个往外复制比较蹩脚的办法:

:set mouse=v

这样鼠标就可以变成文本选择指针的样子,可以选择选择字体,然后点右键选复制,或者CTRL+SHIFT+C,但如果mouse=a这种模式下的话选择之后,右键的复制是灰色的,当然这种情况复制如果有行号的话行号也会被复制进去,所以在复制前先把行号关了,复制完再打开,这办法貌似也能凑合,但着实太不专业,而且太麻烦,远不如用gvim的“+y这种来得方便,“+y这个很多推友表示是可以的,但在我这里不可以,刚经@multiple1902指点,有可能是vim编译的问题。

查看了一下vim版本相关信息:

vim --version

发现clipboardxterm_clipboard这些选项都是不可使用的功能,这样看来果然是编译问题了,slackware讲求KISS,编译的时候没有加入该选项也可以理解,于是从vim官网svn上check下来源码(话说我为啥check下来的是7.2呢,难道7.3还没有stable…),重新编译。

编译的时候必须要选上的选项一个是–enable-multibyte,如果没加这个选项的话,中文应该就会乱码了。
另外关于剪贴板相关的选项,具体我也不清楚是哪一个,看了下几个相关的选项觉得最有可能是的是–enable-xim,只加了这两个选项之后编译完测试发现vim已经可以和系统剪贴板之间共享数据了,“+y可以使用了,世界一下子就清爽了很多,于是重新加完整选项编译:

./configure --prefix=/usr \
            --sysconfdir=/etc \
            --enable-tclinterp \
            --enable-pythoninterp \
            --enable-perlinterp \
            --enable-rubyinterp \
            --enable-cscope \
            --enable-multibyte \
            --enable-xim \
            --enable-gtk2-check \
            --enable-fontset \
            --with-x

OK,编译完成之后removepkg vim删掉之前slackware安装包中提供的vim,然后用makepkg打包安装,哎呀,说起包管理方式我还是最喜欢slackware的tgz包,虽然没有debian的apt那么华丽,但简洁就是美啊。

vim安装完之后已经可以用了,但存在一个问题,vim退出之后终端便会乱码,到网上搜了半天各种关于ubuntu下的解法,拿到slackware上来完全不适用,命令啦路径啦什么的根本找不到,最后搜到一个非常简单的解决办法,说是这个问题是因为gnome-terminal标题名称的不标准,我矁了一眼标题写着“终端”两个字,给出的解决办法是在前后各加一个空格,让系统让为它是英文,我直接把它改成了Terminal,然后再启动vim然后退出就没有问题了。

总算解决了我对于vim的怨念,一直以为是vim的问题,没想到竟然是slackware打包的问题。

分类: Linux 标签: ,

武汉Deepin Linux DAU会议见闻

六月 1st, {2011 7 条评论 9,309 人阅读过  

上次在ubuntu11.04 release party北京站遇到deepin linux负责人刘文欢,他也就是deepin本人,邀请我去参加上个周末在武汉举行的deepin linux DAU大会,当时没有马上答应他,因为怕实验室太忙时间安排不开,后来跟领导商量了下领导表示支持,于是就趁周末跑了过去,一方面是希望能见到开源社区的朋友,另一方面也是很想看看deepin这个出自国人之手的linux发行版会做到什么水准。

会议到场人数很多,我作为特邀嘉宾很惭愧地坐在了前排,会议第一部分是deepin主题演讲,deepin操作系统创始人hiweed介绍深度的发展以及现状,接着是深度软件中心的主要开发者王勇介绍软件中心的相关情况,我个人感觉软件中心还是一个很不错的软件,虽然看上去很容易让人联想到360的软件中心,但不能不说这确实是一个很符合用户使用习惯的软件,从软件的搜索和安装都比ubuntu软件中心要舒服一些,当然这也是我个人的感受,据deepin介绍,软件中心的开发者王勇只有22岁,而且并没有读过大学,当时我就对他特别敬佩,像我们这些读了这么多年书现在还是这样技术平平的人真应该感到惭愧。最后由deepin本人介绍开源社区的管理与运营,让大家对深度这个社区有了一个比较深入的认识。

会议的第二部分是主题嘉宾演讲,第一位是国内开源界的名人袁萌教授,讲永中Office的事情,袁萌可以说是相当有争议的人物了,之前在ubuntu 10.10和11.04的release party现场都见过袁老出现,而且对于这种开源活动袁老似乎每次都不会缺席,这种活动每次出现的为数不多的老年人身影也就只有袁老了,但不管是他在新浪博客上还是在其它地方,大家对他的评论都是褒贬不一,我之前对袁老不熟悉,后来在twitter上打听袁老的事情,有人表示袁老人不错,但口头老挂着永中和U盘的事情就让人有点烦了,确实,袁老讲话我听不太明白(口音原因),但言谈中总会提到永中和U盘的事情,我对此到没什么特别的看法,可能年纪大了人会比较偏执,遇到自己觉得好的东西就会一直推崇。再看他的新浪博客,有人支持也有人很负面地骂,确实让人感觉到袁老真是中国开源界最有争议的人物,其实我觉得像袁老这样一位古希老人,不图名利,仍然能对中国的开源事业如此热心,已经实属不易了,即便大家对他的观点不认同,也不至于用那么偏激的语言去骂他,除非你让我去相信这样一位风烛残年的退休老教授还在用某种低劣的手段去谋取私利,与袁老见面听他言谈,感觉他人非常正直,绝不是什么小人,所以我觉得大家可以不喜欢他,但真的没有必要去骂他。

会议袁老讲完后我也给大家就我的一些经历做了个小报告,简单介绍了一个飞信的开发过程以及我个人的Linux使用经验等,接下来是中科大的张成同学讲在校园同推广Linux,张成是mirrors.ustc.edu.cn的现任维护者,中科大开源协会的副会长,感觉中科大的开源协会做得蛮不错的,大家都很热心地在做一些很有意义的事情,张成技术也非常不错,再一次让我表示汗颜。再之后便是在场的用户提问,具体都问了哪些问题我也记不清了,我也没有刻意地去做会议记录。

会议结束后第二天晚上我和deepin在他们公司单独聊了两个多小时,deepin确实是想在Linux发行版这一块做些事情出来的,在中国做这样的事情难免会遇到种种阻力,包括舆论上的政策上的等等,红旗这样一个烂到根的公司似乎让国人对国产Linux发行版很是绝望,雨林木枫反对的人也很多,我到不太了解原因是什么,我个人不太喜欢它是因为它之前山寨了Windows的UI来适应中国用户的使用习惯,其实说起来如果没有什么版权协议的问题的话也没什么不好。做操作系统是个很漫长的过程,不可能在一两年内就得到用户的普遍认可,即便是ubuntu也是经历了一个长期的过程,Canonical公司也出资做了那么久的公益,说实话,哪家做Linux的公司纯粹做公益我们都没法相信,包括Canonical也是想用ubuntu做出一个品牌再去拓展其它的业务,如ubuntu server. 当然,深度的经济实力远不如Canonical,但做发行版在最开始是很难有经济回报的,我们所能期望的就是深度能坚持下去,毕竟深度和红旗是两家完全不同性质的公司,应该不会像红旗那样腐化,而做这样一个发行版也一直是hiweed和deepin的梦想,其实我个人还是对他们挺有信心的,即便中国人做不出来自己自主研发的操作系统,能出一个被国际认同的Linux发行版也确实是一件好事。

我是站在一个中立的立场,我支持我认为好的东西,如果有一天深度变成了红旗那我也会跟着去骂的。当时deepin在北京给我演示深度系统的时候我真地觉得很不错,起码它降低了新手的技术门坎,通过虚拟化的手段让OFFICE和QQ都跑在了上面,可以说这两个软件对很多新用户来说都是很大的壁垒,这个问题解决了就解决了很多新手的烦恼,我个人觉得任何一家第三方的OFFICE都很难与MS OFFICE兼容,即便是永中它的公式编辑器也完全跟不上。他们没有集成这两款软件,也就不涉及到版权协议之类的问题了。

总之这一行还是受益匪浅的,希望几年之后deepin能成为让国人为之骄傲的发行版,当然也希望它千万不要成为第二个红旗。

分类: Linux 标签: ,

linux终端中输出彩色字体(C/SHELL)

十二月 15th, {2010 3 条评论 14,703 人阅读过  

这几天在用libvlc的时候看到它在terminal里面输出彩色字体觉得挺好玩的,以为是用ncurses实现的,后来一查原来用ANSI C的转义字符就可以实现,不过好现只在linux下有效吧, windows神马的貌似不行,把项目终端凌乱的输出信息整理了一下,关键字符也都用彩色显示,看上去舒服多了,写一下用法以防止以后忘了再去查。

先把控制码列出来(从网上搜来的):

\033[0m               关闭所有属性
\033[1m                       设置高亮度
\033[4m                       下划线
\033[5m                        闪烁
\033[7m                        反显
\033[8m                        消隐
\033[30m----\33[37m 设置前景色
\033[40m----\33[47m 设置背景色
\033[nA                        光标上移n行
\033[nB                       光标下移n行
\033[nC                       光标右移n行
\033[nD                       光标左移n行
\033[y;xH                     设置光标位置
\033[2J                        清屏
\033[K                         清除从光标到行尾的内容
\033[s                          保存光标位置
\033[u                          恢复光标位置
\033[?25l                      隐藏光标
\033[?25h                     显示光标 
背景色:
40:黑 41:深红 42:绿 43:黄色 44:蓝色 45:紫色 46:深绿 47:白色
前景色:
30:黑 31:红 32:绿 33:黄 34:蓝色 35:紫色 36:深绿 37:白色

控制字符是打开某种样式,输出完成时需要再关闭样式才能使terminal恢复到原来状态,简单例子:

printf("\e[32m%s\e[0m\n", "hello world");

\033\e是一回事,使用\e会更简单一些,输出为绿色字体,如下图:

\e[32m为打开绿色前景色样式,\e[0m为关闭所有样式,如果未关闭,则所有输出字体均为绿色前景色,如下代码:

	printf("\e[32m%s\e[0m\n", "hello world");

输出效果如下:

绿色高亮代码如下:

printf("\e[32m\e[1m%s\e[0m\n", "hello world");

输出效果如下:

另外光标移动的控制码在输出类似于下载进度的信息时用得到。

在shell中也可以直接用echo输出,需要加-e选项打开转义字符解释,如输出高亮的绿色字体为:

echo -e "\e[32m\e[1mhello world\e[0m"

其它的我也没怎么看,觉得也就改变字体颜色和移动光标位置能用得到,觉得挺好玩的就写下来以后忘了查一查。

分类: Linux 标签: , ,

linux网络编程手记

十二月 12th, {2010 4 条评论 12,920 人阅读过  

做linux下的网络编程有一段时间了,中间遇到过很多问题,其中不少是因为自己对网络编程和网络协议的一些基本概念搞不清楚,趁着今天没心情干活就把自己在网络编程方面的理解和一些经验总结一下,Request For Comments。

在诸多的网络协议中接触的最多也最紧密的无疑是TCP和UDP,SCTP之前因为项目原因也研究过,不过最终由于方案修改给抛弃了,TCP年代已经很久远,在网上的资料也非常多,而且我感觉它是一种非常复杂的协议,感觉要把编好基于TCP的程序光简单地了解几个socket API是不够的,刚开始接触网络编程的时候自己确实也吃了不少苦头,后来我还专门拿时间出来阅读了一下RFC,再加上长时间的实践总算也对TCP有所了解,把自己的一些经验和教训都总结一下。

首先说一下TCP的状态转移图,这个应该是很重要的,了解TCP运行周期的各种状态才能更好地运用netstat之类的应用程序去对程序进行调试,我这里收藏了一张图,是TCP的状态图,记不清是从哪里找来的,也不知道直接版权该给谁,但这张图应该最终是出自于UNP第一卷的,那copyright就是UNP了吧。

1.TCP连接状态

连接建立的几个状态没什么可说的,TCP的三次握手众所周知,更重要的是TCP连接中止的几个状态,应该可以说是连接中止需要四次握手吧。

当Client调用close函数主动关闭socket时,连接状态被标记为FIN_WAIT_1,Server在收到FIN之后read函数会返回0,这里server知道Client已经关闭连接,回复ACK,这里client连接状态被标记为FIN_WAIT_2,接下来Server调用close函数关闭连接,这时候Server向client发送FIN,Client收到之后将状态标记为TIME_WAIT,并回复ACK。

TIME_WAIT这个状态存在的意义在于Client回复的ACK未必会被Server收到,可能在传输过程中导致包的丢失,而这里Server未收到ACK之后会重新向Client发送FIN,如果client未将状态标记为TIME_WAIT而是直接标记为CLOSED,则Server发送的FIN会直接收到RST,导致Server端的发送错误,因此Client需要保证有一个TIME_WAIT状态,而这个状态会持续两位的MSL(最大段生命周期),从而保证Server成功发送FIN并发送ACK,为了保证两个数据段传输的最大时间,因此TIME_WAIT持续的时间为两倍的MSL。

Server在收到第一个FIN之后会将状态标记为CLOSE_WAIT,此时是client主动关闭连接,这里Server也需要调用Close给Client发送FIN(如上所述),之后Server的状态标记为LAST_ACK,表示Server正在等待Client发送的最后一个ACK,当Server收到最后一个ACK便会将连接标记为CLOSED,这时连接结束。TIME_WAIT这个状态和套接字的SO_REUSEADDR选项是有关系的,这个留做后面讨论。

2.TCP连接异常情况

TCP连接异常分为很多种情况,无论是客户端程序还是服务器端程序都需要考虑周全的。

Server在连接的过程中程序崩溃或者CTRL+C中止程序,或者kill接Server进程。这时会导致Server立即发送一个FIN数据包给Client,Client如果此时正在调用recv函数,则recv函数返回0,表示服务器已关闭连接,如果Client调用send函数继续向Server发送数据,Server在收到后会回复RST,而此时send方法会触发SIGPIPE信号,表示通信管道已断开,在程序中如果对该信号不做处理则会导致程序的崩溃,一般在程序开始时会忽略此信号,则在这种情况下send函数会返回-1,表示发送失败,处理SIGPIPE的代码如下:

前几天实验室这个破项目非要加上什么流媒体的功能,简单起见使用了VLC来实现,客户端这边就得需要把相关的播放界面整合到现有的界面里面来,之前的客户端UI我都是用GTK实现的,没办法,GTK用得比较多,相对熟练一些就用GTK来做了,没想到要把VLC整到GTK里面来那么麻烦,原生的libvlc是不支持GTK的,需要加一层libvlc-gtk,从网上好不容易下载到了libvlc-gtk的源码,从哪里下的也记不清了,反正就是零散地几个文件,没有README甚至连Makefile都没有,没办法首先得先写个Makefile把它编译一下,libvlc-gtk一共有八个文件,Makefile如下:

struct sigaction sa;
sa.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &sa, 0 );

另外在这种情况下select函数也会立即返回,socket描述符会被设置,而试图从该socket中recv数据,则会返回-1。

另外一种情况是Server系统崩溃或者网络直接异常或断开,这时候Server不可能再给Client发送FIN包,而Client调用send函数后会导致数据包一直重传直接超时后返回-1,而recv函数也会一直阻塞直接超时后返回-1。这种情况就很难判断是Server端进程关闭还是网络异常,这种情况一般会用TCP的KEEP ALIVE机制,每隔一定的时间向对方发送一个只有一字节数据内容的数据包,对端收到后会返回一个ACK,以此来确保连接正常,如果未收到ACK,会尝试重传,直到重试规定次数后可以将与对端的连接标记为断开,send和recv将会返回-1。KEEP ALIVE的使用方法如下:

int tcp_keep_alive(int socketfd)
{
	int keepAlive = 1;
	int keepIdle = 10;         /* 开始发送KEEP ALIVE数据包之前经历的时间 */
	int keepInterval = 10;   /* KEEP ALIVE数据包之前间隔的时间 */
	int keepCount = 10;     /* 重试的最大次数 */
 
	if(setsockopt(socketfd , SOL_SOCKET , SO_KEEPALIVE
				,(void*)&keepAlive,sizeof(keepAlive)) == -1){
		debug_info("set SO_KEEPALIVE failed\n");
		return -1;
	}
 
	if(setsockopt(socketfd , SOL_TCP , TCP_KEEPIDLE
				,(void *)&keepIdle,sizeof(keepIdle)) == -1){
		debug_info("set TCP_KEEPIDEL failed\n");
		return -1;
	}
 
	if(setsockopt(socketfd , SOL_TCP , TCP_KEEPINTVL
				,(void *)&keepInterval,sizeof(keepInterval)) == -1){
		debug_info("set TCP_KEEPINTVL failed\n");
		return -1;
	}
 
	if(setsockopt(socketfd , SOL_TCP , TCP_KEEPCNT
				,(void *)&keepCount,sizeof(keepCount)) == -1){
		debug_info("set TCP_KEEPCNT failed\n");
		return -1;
	}
	return 1;
}

上面这个函数只针对Linux,昨天有网友告知在Mac OS上TCP_KEEPIDLE ,TCP_KEEPINTVL, TCP_KEEPCNT这些宏将未定义。另外对于这些参数的设置也是需要注意的,很多系统中它们的设置并不是对单个socket描述符起作用的,而是该机器上的所有socket描述符起作用的,所以这个需要注意(这个是从UNP里面看到的)。

3.关于字节顺序
Linux的主机字节顺序是采用little-endian字节顺序,而网络字节顺序是采用big-endian字节顺序,字节顺序转换是必需的。写了一个小程序来检测字节顺序,不知道对不对,Request For Comment.

#include 
 
int main(int argc, char **argv)
{
	short s = 0x0102;
	if((*(unsigned char*)&s) == 2)
		printf("little endian\n");
	else if((*(unsigned char*)&s) == 1)
		printf("big endian\n");
	else
		printf("unknown endian\n");
 
	return 0;
}

3.关于send和recv

写过socket程序的人肯定都会知道send和recv函数并不会总是返回要求发送或读取的字节数,如:

int ret = recv(sk, buf, 2096, 0);

这句话并不总是读取到完整地2096个字节,相反地,大多数情况下都不能将buf读满,recv只能返回当前可以读取到的字节数,如果协议规定本次读取肯定会读取到N个字节,那我一般的做法会写一个这样的函数来确保读取到固定的字节数:

int buf_recv(int sock, void *buf, size_t len, int flags)
{
	int n, ret;
	if(len == 0) return 0;
	for(n=0;n!=len &&(ret = recv(sock, buf+n, len-n, flags)) != -1 &&ret; n += ret);
	return (n!=len)? -1:n;
}

关于这两个函数还有很重要的一点是应该尽可能大地一次发送或接收更多地数据,当然前提是缓冲区中有这些数据的话,原因很简单,当通信链路很好的时候数据可能会填满系统缓冲区,而recv便是从缓冲区中读取数据,这时候一次读取更多地字节就意味着可以少调用几次recv函数,而这些函数通常都是调用了系统调用,需要进行内核态和用户态上下文的切换,也就意味着多调用几次recv会带来额外的开销,之前写的一个代理服务器的程序数据传输速度一直很低,后来修改了recv和send的缓冲区大小后速率提高了近一倍。

4.关于非阻塞模式

一般应用的时候都是使用阻塞式IO,至少我在大多数情况下都用的阻塞式IO,非阻塞很少应用,但存在便我价值,我用到的非阻塞IO的情况一般是用来进行超时connect,首先将socket设为非阻塞模式,connect立即返回-1,此时已向对端发送FIN,而并未来得及收到任何ACK,于是直接返回-1,但并不代表连接失败,errno会被置为EINPROGRESS ,表示连接正在进行中,然后通过select来设置socket可写的超时时间,如果规定时间内可写,且socket并无出错,则表示连接成功,socket出错则表示连接失败,或规定时间内不可写则表示连接超时,简单地写了如下代码:

#include
#include
#include
#include
#include
#include
#include 
 
int main(int argc, char *argv[])
{
	int                sk;
	int                flags;
	int                err = 0;
	int                ret;
	socklen_t          len;
	struct sockaddr_in addr;
	fd_set             fd_write;
	struct timeval     tv;
 
	if( (sk = socket(AF_INET, SOCK_STREAM, 0)) == -1 ) {
		perror("socket");
		return 1;
	}
 
	if( (flags = fcntl(sk, F_GETFL, 0)) == -1 ){
		perror("fcntl GET flags failed");
		return 1;
	}
 
	if(fcntl(sk, F_SETFL, flags | O_NONBLOCK) == -1) {
		perror("fcntl SET flags failed");
		return 1;
	}
 
	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = inet_addr("59.64.129.169");
	addr.sin_port = htons(808);
 
	if(connect(sk, (struct sockaddr*)&addr, sizeof(addr)) == -1	) {
		if(errno != EINPROGRESS) {
			perror("connect");
			return 1;
		}
		FD_ZERO(&fd_write);
		FD_SET(sk, &fd_write);
		tv.tv_sec = 5;
		tv.tv_usec = 0;
 
		ret = select(sk + 1, (fd_set*)0, &fd_write, (fd_set*)0, &tv);
 
		if(ret > 0){
 
			if(FD_ISSET(sk, &fd_write)) {
				len = sizeof(int);
 
				if(getsockopt(sk, SOL_SOCKET, SO_ERROR, &err, &len) == 0) {
					if(err == 0) { printf("connect success\n"); return 0; }
					else { fprintf(stderr, "connect:%s\n", strerror(err)); return 1; }
				}else{
					fprintf(stderr, "getsockopt:%s\n", strerror(err));
					return 1;
				}
			}else{
				fprintf(stderr, "connect(FD_ISSET) failed\n");
				return 1;
			}
 
		}else if(ret == 0) {
			fprintf(stderr, "connect timeout\n");
			return 1;
		}else {
			fprintf(stderr, "connect(select):%s\n", strerror(errno));
			return 1;
		}
	}else{
		fprintf(stderr, "connect:%s\n", strerror(errno));
		return 1;
	}
	return 0;
}

5.关于select多路复用

select是网络编程中很常用的函数,用来进行IO多路复用,但之前我一直忽略了一个问题,当select返回时会将本次检查中不可用的描述符(如不可读或不可写)的描述符从描述符集中删除,只保留当前可用的描述符,在对多个socketfd进行利用的时候需要注意,每次循环select之前都需要在select之前用FD_SET重新设置描述符,否则之后便只能返回第一次可读的描述符了。

6.关于UDP广播

UDP广播这个也简单说一下,首先255.255.255.255这个地址是不能被路由的,只能被本物理网络的数据包接收。UDP广播之前需要给socket设置SO_BROADCAST选项:

int brodopt = 1;
setsockopt(cp_usock, SOL_SOCKET, SO_BROADCAST, &brodopt, sizeof(brodopt));

UDP广播需要注意的一点是广播接收时接收端bind的本地地址的问题,接收端必须绑定INADDR_ANY这个地址才可以接收广播包,如果是绑定的某个特定的地址则无法接收广播包。

OK,简单说这么几条,都是我编程时候遇到的经验总结,以后再遇到什么问题再接着补充。

分类: Linux 标签: , ,

抓取飞信协议数据包的bash脚本

十二月 11th, {2010 9 条评论 8,880 人阅读过  

昨晚想写个抓飞信协议包的脚本,结果刚写了一点就去看电影了,今天把它给完善了一下贴出来,也顺便可以帮助大家更好地理解飞信协议,也为了更多的人能够加入到openfetion的开发中来。

其实不是我不懂“工欲善其事必先利其器”这个道理,只是之前在写openfetion的时候我只能跑到windows下去抓包,windows里面的什么vbs之类的脚本我也不会写,就用最笨的办法用wireshark把数据包抓出来然后复制到txt中,现在在linux下可以抓openfetion的数据包,它的包格式与官方飞信相同(这句是废话,要不然也不可能实现互联互通)。

简单地说一下这个脚本,其实不用说它也很简单,就这么几行,飞信在登录的时候需要向一台sipc服务器注册,随后主要的数据包都是与这台服务器之前交换的,而这台服务器我想肯定也是分布式架构了,不同的飞信号会对应于自己的sipc服务器,而服务器的地址是通过配置文件传递给客户端的,客户端在注册之前先向nav.fetion.com.cn这个地址POST一个http请求,随后服务器会响应一个大的xml,之前版本的openfeion并没有对这些数据做本地缓存,所以在每次登录的时候都需要获取这个配置文件,所以经常会有用户反应卡在“正在下载配置文件”这一步进行不下去了,现在的方法是在本地把需要用到的字段做了缓存,再次登录的时候用缓存版本号查询服务器,如果版本号是最新则会返回一个很小的xml结构,速度当然也会比完全下载快得多。

接着说这个脚本,请求到配置文件之后便会得到飞信号对应的sipc服务器地址,之后就用tcpdump来抓取通往这个地址的包和来自这个地址的包,然后就简单做了一下解析。

#!/bin/sh
#written by @levin108
#This script is used to capture the packets of fetion client,and help to anlysis fetion protocol.
#You need to have openfetion installed in your computer,or maybe libfetion,I don't know,whatever...
 
if [ $UID -ne 0 ]; then
	echo "perminission denied,you must be root to run this script"
	exit 1
fi
 
if [ $# == 0 ]; then
	echo -n "please input the mobile number:"
	read mobileno
else
	mobileno=$1
fi
 
if [ ${#mobileno} -ne 11 ];then
	echo "wrong mobile number"
	exit 1
fi
 
protocol_version="4.0.2510"
config_uri="http://nav.fetion.com.cn/nav/getsystemconfig.aspx"
config_body="<config><user mobile-no=\"$mobileno\"/> \
			<client type=\"PC\" version=\"$protocol_version\" \
			platform=\"W5.1\"/><servers version=\"0\"/> \
			<parameters version=\"0\"/><hints version=\"0\"/></config>"
 
echo "Getting fetion sipc servr address..."
 
config_xml=`curl -d "$config_body" -A "IIC2.0/PC $protocol_version" $config_uri 2> /dev/null`
proxy_endpoint=`echo $config_xml | sed 's/.*<sipc-proxy>\([^<]*\).*/\1/'`
proxy_ip=`echo $proxy_endpoint | sed 's/:[0-9]*$//'`
proxy_port=`echo $proxy_endpoint | sed 's/.*://'`
 
echo "Sipc server address : $proxy_ip:$proxy_port"
echo "Start capturing,now start your fetion client and login."
echo
 
tcpdump -n -A -l -t -s 0 tcp and host $proxy_ip \
	and port $proxy_port or host nav.fetion.com.cn 2>/dev/null | awk '
/^IP/{
	if($NF == 0) {
		is_data_seg = 0;
	} else {
		printf("\n%s ----> %s\n", $2, $4)
		printf("-----------------------------------\n\n")
		# whether it is a data segment
		is_data_seg = 1;
		# eth/ip/tcp header length
		bytes_before_protocol = 52;
	}
}
 
!/^IP /{
	if(is_data_seg) {
		if(length($0) < bytes_before_protocol) {
			bytes_before_protocol -= length($0)
			next;
		}
		if(length($0) >= bytes_before_protocol && 
			bytes_before_protocol != 0) {
			$0 = substr($0, bytes_before_protocol);
			bytes_before_protocol = 0;
		}
		print $0
	}
}
'

分类: Linux 标签: , , ,

OpenFetion V2.0正式版发布

十月 24th, {2010 74 条评论 21,848 人阅读过  


经过近一个月的修改测试,Openfetion 2.0正式版今天release出来了,相比于之前的1.x版本相比,2.0有更多的优点和特性,最重要的是2.0稳定性较之于之前版本登录速度更快,稳定性更高。

这次版本主要集中在解决历史版本中所存在的登录崩溃,运行时崩溃的问题,以及用户所普遍反映的登录速度过慢的问题,引入了SQLITE3来实现了数据的本地化,使登录过程需要下载的数据量很小,从而大大提高了用户登录速度,也因为实现了数据的本地化,新版本也增加了离线和离线登录功能。

新版本另一个重要的特性是检测网络状态,可以实现断线检测并自动重连,失败时会显示用户离线,而不是之前离线时直接退出程序。检测网络状态需要NetworkManager的支持,此依赖库为可选,如果安装时disable,则不具有自动重连功能。

另外新版本增加了空闲时间自动离开功能,空闲时间目前固定为3分钟。此功能需要XScreenSaver的支持,此依赖库也为可选。

另外新版本再一次更换了图标,新图标由@riku设计,由@xhacker修改,感谢二位对OpenFetion做出的贡献。

下面是ChangeLog:

2010-10-24 levin

* 修复了登录和运行时的崩溃问题
* 修复了群发短信时的崩溃问题
* 修复了添加好友时的崩溃问题
* 添加了数据本地化,实现了离线登录功能
* 添加了断线自动重连功能
* 添加了空闲时间自动离开功能
* 添加了关闭上线提示的功能
* 优化了登录过程,登录速度更快
* 更换了新版图标,更美观

程序添加的依赖库为libsqlite3,NetworkManager,XScreenSaver,Ubuntu下的安装方法如下:

sudo apt-get install libxml2-dev
sudo apt-get install libgtk2.0-dev
sudo apt-get install libssl-dev
sudo apt-get install libnotify-dev
sudo apt-get install libgstreamer0.10-dev
sudo apt-get install intltool
sudo apt-get install libsqlite3-dev
sudo apt-get install libnm-glib-dev
sudo apt-get install libxss-dev

ubuntu用户推荐使用happyaron制作的PPA安装,该PPA于10.24日晚将会更新到最新版本,安装方法如下:

sudo apt-add-repository ppa:happyaron/ppa
sudo apt-get update
sudo apt-get install openfetion

Fedora用户依赖库安装方法如下:

pkcon install gcc gstreamer-devel gtk2-devel libxml2-devel openssl-devel intltool 
sqlite-devel NetworkManager-devel libXScrnSaver-devel libnotify-devel

期待各方打包人士制作相关安装包

源码下载地址:
http://code.google.com/p/ofetion/downloads/list

Follow Me @levin108

分类: Linux 标签: , , ,

写给OpenFetion用户(相关说明和常用问题汇总)

九月 11th, {2010 86 条评论 26,208 人阅读过  

OpenFetion从去年发布第一个版本到现在已经正式更新了将近10次,首先感谢大家对OpenFetion的支持,最初开发这个软件的时候是因为在Linux下找不到用得舒服的飞信客户端软件,而且也想找点事情打发一下无聊的研究生时光,突发奇想就写了这么个小东西,第一个版本刚发布的时候错误百出,当时没有专门做过测试,只是在自己机器上用自己的账号跑起来没有问题,用了几天就发布了,结果是网友报各种各样的bug,这也是自由软件的好处,总会有很多热心的网友帮助你测试软件,也正是有了广大网友的支持我一直以来才会不断地维护更新着它。

关于OpenFetion的版权问题

OpenFetion是遵循GPL协议的共享软件,但一直惭愧的是本人不善美工,在早期版本里面用了很多飞信官方的小图标,直到最近这个问题才开始慢慢地解决,也正是因为图标问题我到现在才迟迟没有正式发布新版本,如果大家在使用Openfetion的时候遇到登录问题或者想试用一下新版本里面的功能,可以到svn上下载最新开发版本使用:

$svn checkout http://ofetion.googlecode.com/svn/trunk/ ofetion-read-only

而且我们推荐使用SVN上的版本更新您的软件,因为这样可以在新版本发布之前最快地体验到新版本中的功能,更及时地解决旧版本中存在的BUG。

关于OpenFetion的安装包的问题

之前的版本都是由我一人维护,deb和rpm的包我都不会打,而且一直用slackware这些机制的包都不支持,所以也就没有在软件发布的时候及时推出这些相关的安装包,googlecode上经常会有热心的用户提供打好的优秀的安装包,所以大家可以到google code上去找用户提交的相关的安装包和安装脚本,另外ubuntu中文论坛的happyaron长期以来一直负责OpenFetion的PPA制作,为广告用户提供了方便,在这里向他表示感谢,另外这里再说一下happyaron的PPA的使用方法:

10.04:deb http://ppa.launchpad.net/happyaron/ppa/ubuntu lucid main

9.10: deb http://ppa.launchpad.net/happyaron/ppa/ubuntu karmic main

9.04: deb http://ppa.launchpad.net/happyaron/ppa/ubuntu jaunty main

8.10: deb http://ppa.launchpad.net/happyaron/ppa/ubuntu intrepid main

8.04: deb http://ppa.launchpad.net/happyaron/ppa/ubuntu hardy main

使用方法是选择您的发行版版本号对应的代码拷贝到源列表中,比如Ubuntu 10.04,则将”deb http://ppa.launchpad.net/happyaron/ppa/ubuntu lucid main”拷由到/etc/apt/sources.lst中,然后先用下面的代码获取密钥:

$sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys DDA4DB69

接下来在Console中输入:

$sudo apt-get update
$sudo apt-get install openfetion


如何卸载OpenFetion

需要注意的一个问题是,新版旧本的OpenFetion之间可能存在冲突,在安装新版本的时候如果和旧版本安装目录不一致则最好先把旧版本删除再安装,configure的默认安装prefix是/usr/local/,如果是使用PPA安装或者使用的安装脚本则很可能将prefix设成了/usr目录下,假设默认安装路径是/usr/local,那么需要删除二进制可执行文件和libofetion库文件,它们存放的目录是/usr/local/bin和/usr/local/lib目录下libofetion开头的库文件,当然我也提供了uninstall脚本。

下载地址:http://ofetion.googlecode.com/files/ofetion_uninstall.sh


关于OpenFetion的编译安装问题:

OpenFetion链接了几个共享库,分别是

libgtk2.0-dev(提供UI支持),
libssl-dev(提供加密安全支持),
libxml2-dev(提供xml创建解析支持),
libnotify-dev(提供gnome notification消息提示支持,可选),
libgstreamer0.10-dev(提供声音提示功能支持,可选)
intltool(提供国际化的支持)

注意:编译安装必须使用开发版本,后面不带dev的包是不行的(为了解决各种技术水平的用户的疑问,请允许我使用这种说法)。

这几个包在Ubuntu下我试着安装过,很简单,其它的发行版我手头实在找不到,大家可以自己想办法,肯定不难。
Ubuntu下的安装方法:

$apt-get install libxml2-dev
$sudo apt-get install libgtk2.0-dev
$sudo apt-get install libssl-dev
$sudo apt-get install libnotify-dev
$sudo apt-get install libgstreamer0.10-dev
$sudo apt-get install intltool

Fedora中的安装方法:

pkcon install gcc gstreamer-devel gtk2-devel libxml2-devel openssl-devel intltool

这些包都安装就绪之后就可以编译安装OpenFetion了,

$./configure --prefix=/usr
$make
$make install

或者

su -c "./configure=/usr && make && make install"

编译安装之前需要安装dev版本的共享库,其中libgtk2.0-dev可能会占几十M的空间,没有预安装这些库并且舍不得磁盘空间的用户就只有使用PPA安装或者到Google Code上找网友打好的安装包安装了。

关于如何调试OpenFetion

坦城的讲,OpenFetion现在仍然存在很多BUG,也仍然有用户报“段错误”,当然出现这些问题的时候我希望能得到您的帮助,如果能帮我高度一下程序给出断点的位置,无疑能让我更快地定位BUG,然后修复它们,其实调试的过程很简单,在终端中输入如下的命令:

levin@slack:~$ gdb openfetion
GNU gdb (GDB) 7.1
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-slackware-linux".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /usr/local/bin/openfetion...done.
(gdb) run
 
然后程序开始运行,当程序由于BUG运行停止后,再输入如下命令:
(gdb)back
然后把出现的断点信息发送给我就可以了,我会在最短的时间内修复。


关于OpenFetion其它的几点说明:

1.官方飞信支持同一个好友属于多个不同的分组。很惭愧,也很抱歉,我一直都不知道原来飞信支持这个功能,所以当时开发的时候就只按一个好友对应一个分组来开发的,这也导致了那些将一个好友同时放到不同的分组中的用户在登录之前出现段错误,这个BUG存在于当前1.8版本以及之前的所有版本中,在这里,对那些因为存在类似情况而不能使用OpenFetion的用户道歉,这是我协议分协过程中的失误,这个问题在最新的SVN版本中已经解决,happyaron的PPA中的最新版本的OpenFetion也解决了这个问题,但是我要强调的是OpenFeiton暂不支持同一个好友属于多个分组,为了解决这些用户的登录问题,我暂时将这些好友拿出来放到了未分组里面,很多网友最近过来报这个BUG,其实这还不算个BUG,只是我最近太忙,没时间再去找个windows分析飞信的分组相关的协议,大家可以先这样用一段时间,起码它已经能保证你能登录能正常使用了。

2.OpenFetion安装成功后却不能运行。这个问题是用户提问最多的问题,这个问题解决起来也很简单,表现是安装完成后出现下面的错误提示:

openfetion: error while loading shared libraries: libofetion.so.0: cannot open shared object file: No such file or directory

出现这种问题的原因我在之前的一篇日志里面简单地说了,参考:关于库文件的搜索路径问题

解决的方法也很简单:如果在安装的时候默认路径是/usr/local/或者其它自定义的非系统路径,那么lib就会被安装到相应的路径中去,这时候把你lib所在的路径添加到/etc/ld.so.conf中去,然后在终端中执行

$sudo ldconfig

3.近期移动推出web版飞信,OpenFetion将会何去何从。

其实我真挺希望移动官方可以推出一个用起来舒服方便的Linux版本客户端,而不是模仿腾讯做这种web的客户端,用起来确实很不方便,要是哪天移动推出了官方的Linux版本飞信,而且大家用起来也比OpenFetion这种第三方的客户端舒服,那OpenFetion就没有什么存在的必要了,我也就可以不用花时间去维护它了,最终目的还是使用方便,如果有好用的客户端干嘛还要花时间花精力去开发第三方的客户端,所以我从来没有想过把OpenFetion移植到windows上去,因为那里有官方飞信客户端,功能很完善,而且也比OpenFetion稳定的多。

我开发这个的初衷不是想拿它谋取利益,而且它确实给我带不来什么经济上的利益,虽然我blog上挂了几个谷歌的广告,但几乎没人点,等我从谷歌那里拿到那几百块钱的广告费的时候说不定我儿子都会开发软件了,有三位网友曾给予过我捐助,我的支付宝账户里面现在有40+RMB,钱虽然不多,但那是他们对我的鼓励和支持,想起来是很开心的,因为自己的成果得到了别人的认可,想公开对他们表示感谢,但因为在支付宝里面用的是真名,所以也不太方便公开网友的真实性名,就在这里谢过几位了。

其实开发OpenFetion最初的目的是为了自己给自己用,因为经常用飞信和女朋友聊天,用linux没有个好用的飞信怎么能行,另一个重要的原因也是为了杀时间,当然到了现在还在维护着它,是出于对用户的一种责任吧(哈,听起来很高尚的样子),因为已经有很多人在用它了,放着那些有能力解决的BUG不解决确实是对软件对用户的一种不负责任。

4.OpenFetion是否会支持文件传输功能。

目前来说暂时没有开发文件传输功能的打算,前一段时间分析过飞信文件传输相关的协议,发现实现起来不像我最初想象地那么简单,需要投入较多的时间,现在实验室项目赶得很紧,不像刚开始读研的时候时间总是那么充裕了,空余的时间只能够添加一些小功能,修改一些小bug,这个功能先暂时搁浅,还请大家见谅。


致谢(我觉得应该有这样一个环节)

这里是代表我和所有正在使用OpenFetion的用户向相关的人表示感谢。嗯,首先应该是我女朋友,刚到北京读研的时候她正在边工作边考研,自己一个人很辛苦,说起来也挺内疚的,那时候都不怎么给她发短信,打电话也说不了几分钟,因为那时候飞信刚刚推出现在最新版本的协议,那一个月我把所有的空余时间都拿出来重写OpenFetion了,她能理解我,我感到很欣慰也很感激,虽然一直以来她都对我的技术很不屑。

技术上要感谢的是:

Ubuntu中文论坛的happyaron,他不仅非常及时地更新PPA源,而且还在我的开发上给了很多的建议和意见,有时候也会给我反溃BUG。

wzssyqa 他完成了1.6和1.7版本的i18n,说实话在这之前我对i18n并不了解,有了他的模板我才让现在的版本支持了简体中文和英语两种语言。

liu.dongyuan 他解决了输入法不能输入英文的问题,并做了大量UI方面的改进特别是美工方面都做了很多工作。

xuhdev 他刚刚加入开发小组不久,改进了很多UI上英文的翻译错误(我为我的英语感到可耻)。

对OpenFetion做出贡献的人还有很多,不一一列举了,希望更多的人加到OpenFetion的开发行列上来,人多力量大,这样OpenFetion才能越做越好,为各位热衷开源的朋友提供方便。

加入开发小组或者技术交流

有意向加入开发小组的朋友可以在这里留言,或者邮件给我levin108(AT)gmail.com,或者加我GTalk,或者去推特上给我留言:@levin108,强烈欢迎各位热心网友的加入。

当然有什么问题或者技术交流都可以通过上面的方法联系我,但请不要索要我的QQ号,因为我一个月也就上个一两次,每次持续不了多长时间。

分类: Linux 标签:

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

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

说实话,自己脚本能力太差了,于是利用周末的时候读了读《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 &lt;= 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,512 人阅读过  

近日实验室一台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 标签: ,

linux内核中的tasklet机制

六月 6th, {2010 没有评论 9,273 人阅读过  

tasklet是IO驱动程序中实现可延迟函数的一种首选的方法,一个tasklet只可以在一个CPU上同步地执行,不同的tasklet可以在不同地CPU上同步地执行。

tasklet的实现是建立在两个软件中断的基础之上的,即HI_SOFTIRQ和TASKLET_SOFTIRQ,本质上没有什么区别,只不过HI_SOFTIRQ的优先级更高一些,建立在HI_SOFTIRQ上的tasklet会早于TASKLET_SOFTIRQ执行。

tasklet链表是存放在tasklet_vec和tasklet_hi_vec这两个数组里面的,数组的长度就是cpu的个数,这是两个percpu数组。linux为smp定义了一系列的宏用于初始化获取删除percpu变量

1
DEFINE_PER_CPU(struct tasklet_struct , tasklet_vec)

这个宏的作用是创建一个类型为tasklet_struct类型的tasklet_vec数组,这个数组即属于percpu数据,具体的实现机制我暂时还没有搞明白。

1
__per_cpu_var(tasklet_vec)

根据percpu变量的名字获取percpu数据

创建一个tasklet首先需要创建一个tasklet描述符,即struct tasklet_struct结构体,并用tasklet_init()函数初始化它。
@include/linux/interput.h

1
2
3
4
5
6
7
8
struct tasklet_struct
{
	struct tasklet_struct *next;
	unsigned long state;
	atomic_t count;
	void (*func)(unsigned long);
	unsigned long data;
};

其中count是一个原子变量的锁时数器,大于0时表示当前tasklet被禁止,tasklet_enable()和tasklet_disable()函数通过减少和增加这个字段的值来实现当前tasklet的启用和禁止。

state是tasklet的状态标志,只有两个选项:

@include/linux/interput.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
enum
{
	TASKLET_STATE_SCHED,	/* tasklet已经被调度,但还尚未执行 */
	TASKLET_STATE_RUN	/* tasklet正在执行,只针对SMP有效,单处理器无意义 */
};
 
void tasklet_init(struct tasklet_struct *t,
		  void (*func)(unsigned long), unsigned long data)
{
	t->next = NULL;
	t->state = 0;
	atomic_set(&t->count, 0);
	t->func = func;
	t->data = data;
}

在创建完tasklet描述符之后就需要对tasklet进行调度,即把tasklet描述符插入到tasklet_vec中相应链表中去。调度函数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void __tasklet_schedule(struct tasklet_struct *t)
{
	unsigned long flags;
	/* 在flasgs中保存eflags寄存器的IF标志,并关中段 */
	local_irq_save(flags);
	t->next = NULL;
	/* 将tasklet描述符插入到tasklet_vec链表的尾部 */
	*__get_cpu_var(tasklet_vec).tail = t;
	__get_cpu_var(tasklet_vec).tail = &(t->next);
	/* 激活TASKLET_SOFTIRQ软中断 */
	raise_softirq_irqoff(TASKLET_SOFTIRQ);
	/* 恢复eflags寄存器的值,并打开中断 */
	local_irq_restore(flags);
}

至此tasklet的调度就完成了,对tasklet可延迟函数的处理将交由软中断处理函数处理,下面看TASKLET_SOFTIRQ软中断的处理函数:

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
static void tasklet_action(struct softirq_action *a)
{
	struct tasklet_struct *list;
 
	/* 禁用本地中断 */
	local_irq_disable();
	/* 将tasket_vec中对应的tasklet链表头的地址保存在list临时变量中
	 * 并清空tasklet_vec中的链表,以允许新的tasklet */
	list = __get_cpu_var(tasklet_vec).head;
	__get_cpu_var(tasklet_vec).head = NULL;
	__get_cpu_var(tasklet_vec).tail = &__get_cpu_var(tasklet_vec).head;
	/* 重新启用本地中断 */
	local_irq_enable();
 
	while (list) {
		struct tasklet_struct *t = list;
 
		list = list->next;
 
		if (tasklet_trylock(t)) {
			if (!atomic_read(&t->count)) {
				if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
					BUG();
				t->func(t->data);
				tasklet_unlock(t);
				continue;
			}
			tasklet_unlock(t);
		}
 
		local_irq_disable();
		t->next = NULL;
		*__get_cpu_var(tasklet_vec).tail = t;
		__get_cpu_var(tasklet_vec).tail = &(t->next);
		__raise_softirq_irqoff(TASKLET_SOFTIRQ);
		local_irq_enable();
	}
}

分类: Linux 标签: