存档

2010年10月 的存档

OpenFetion V2.0正式版发布

十月 24th, {2010 74 条评论 22,085 人阅读过  


经过近一个月的修改测试,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 标签: , , ,

sqlite3使用手记

十月 23rd, {2010 5 条评论 16,850 人阅读过  

前几天为了解决openfetion登录速度过慢的问题,决定实现数据的本地化功能,以往采用二进制文件直接写入磁盘的形式效率和灵活性显然远远不够,于是毅然决定采用sqlite3来实现,用过之后才发现sqlite3果然是绝佳的选择,作为一种轻量型的数据库,sqlite3有着它独特的优势,简单易用,而且极为高效,当初在引入这个依赖库的时候还在犹豫,但完成后发现它所带来的用户体验绝对可以掩盖住安装时多一个小步骤的繁琐。

sqlite3第一次用,简单地把自己的使用过程写一下,以后再用到可以参考。

sqlite3对很多通过的SQL语句都支持,像SELECT,UPDATE,INSERT,DELETE等等都支持地很好,只要懂SQL语句就可以用sqlite3。

1,下面是几个比较重要的API函数:

/* 打开数据库,如果不存在则创建一个 */
int sqlite3_open(const char*, sqlite3**);
 
/* 关闭数据库 */
int sqlite3_close(sqlite3*);
 
/* 获取错误信息字符串 */
const char *sqlite3_errmsg(sqlite3*);
 
/* 执行SQL语句 */
int sqlite3_exec(sqlite3*, const char *sql, sqlite_callback, void*, char**);
 
/* 获取SQL查询结果,其实这个函数是不推荐使用的,一方面是因为它不安全,另一方面它不能处理BLOG类型的字段,当然,在这里我在查询的时候还是使用了它,因为没有涉及到多复杂多庞大的数据,这个使用起来又简单,所以就选用了这个方法 */
int sqlite3_get_table(
  sqlite3 *db,          /* An open database */
  const char *zSql,     /* SQL to be evaluated */
  char ***pazResult,    /* Results of the query */
  int *pnRow,           /* Number of result rows written here */
  int *pnColumn,        /* Number of result columns written here */
  char **pzErrmsg       /* Error msg written here */
);

还有复杂一些的API如下,我没仔细看,像sqlite3_get_table这些函数就是由下面这些API组合而成的

INT sqlite3_prepare(sqlite3*, const CHAR*, INT, sqlite3_stmt**, const CHAR**);
INT sqlite3_bind_double(sqlite3_stmt*, INT, DOUBLE);
INT sqlite3_bind_int(sqlite3_stmt*, INT, INT);
INT sqlite3_bind_int64(sqlite3_stmt*, INT, long long INT);
INT sqlite3_bind_null(sqlite3_stmt*, INT);
INT sqlite3_bind_text(sqlite3_stmt*, INT, const CHAR*, INT n, void(*)(void*));
INT sqlite3_bind_text16(sqlite3_stmt*, INT, const void*, INT n, void(*)(void*));
INT sqlite3_step(sqlite3_stmt*);

2,创建自增长类型的字段

CREATE TABLE history (id INTEGER PRIMARY KEY AUTOINCREMENT,
			name TEXT,userid TEXT,message TEXT,
			updatetime TEXT,issend INTEGER);

这个语句中创建的id字段即为自增长的字段,在插入记录的时候只需把id字段写为NULL即可实现其自增长,如:

INSERT INTO history VALUES(NULL,"levin","123456","hello sqlite3","2010-10-23",1);

3.sqlite3的限制读取条数

/* 在其它SQL数据库中SELECT指定条数的记录用如下语句:*/
SELECT TOP 10 * FROM history;
 
/* 而在sqlite3中使用下面语句:*/
SELECT * FROM history LIMIT 10

4.sqlite3的日期函数

sqlite3的日期函数还是很强大的,列举几个常用的。

/* 获取当前时间 */
SELECT DATETIME('now')
输出:2010-10-23 12:10:50
 
/* 获取当前时间偏移 */
SELECT DATETIME('now','+20 days');
输出:2010-11-12 12:12:54
 
/* 获取今年开始时间 */
SELECT DATETIME('now','start of year');
输出:2010-01-01 00:00:00
 
/* 获取本月开始时间 */
SELECT DATETIME('now','start of month');
输出:2010-10-01 00:00:00
 
/* 获取今天开始时间 */
SELECT DATETIME('now','start of day');
输出:2010-10-23 00:00:00

另外,sqlite3里面有个很重要的时间函数,strftime,这个跟POSIX里面的strftime函数很像,也是将日期类型格式化为字符串类型,如:

SELECT strftime('%Y|%m|%d','now');
2010|10|23

它的格式化字符和POSIX的strftime也完全一样,再例如我要查询本月的聊天记录,可以使用下面语句:

SELECT * FROM history WHERE 
strftime('%Y',updatetime) == strftime('%Y','now') AND
strftime('%m',updatetime) == strftime('%m','now') ;

5.写入较大数据时采用事务提高效率
我在应用sqlite3的时候其实只是写入了少量的数据,刚开始觉得效率不是什么大问题,后来有用户反馈说他的290+好友的飞信号在登录时要向磁盘写入几十S的数据,这个效率问题着实需要改善,于是采用事务来处理写入,事务的使用也非常简单,其实也就是下面的语句:

sqlite3_exec(db, "BEGIN TRANSACTION;", 0,0, &errMsg);
 
for(;;){
  insert into.....
}
 
sqlite3_exec(db, "COMMIT TRANSACTION;", 0, 0, &errMsg);

这样一系列地插入语句就可以被作为一个事务来执行,在COMMIT TRANSACTION的时候将插入操作写入磁盘,避免了每次插入记录时频繁地读写磁盘数据库,从而使效率大大提高,据说可以比单纯地插入快1000倍,这个我无从考证,不过我这里确实快了很多,几百条记录可以瞬间写入。

就在昨天一本科同学还问我会不会sqlite,我正好前两天也用了,就跟她交流了下,她问我怎么写入多条数据,呃..这个问题很简单,就是循环,在程序里面循环,想在SQL里面循环用sqlite3是做不到的,因为sqlite3忽略了很多数据库很重要的特性,它不支持存储过程,而且也没有其它数据库地高并发性,因此有的时候我多个线程同时访问同一个数据库文件的时候,便会报错说database is locked。

OK,以上只是我个人使用过程中的一点小小地总结,拿过来就用,也没做多少研究,sqlite3一些复杂的机制都没有去了解,把这些基础的东西写下来,给自己做个备份,说不定哪天还会再用到。

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

Openfetion近期开发手记(相关功能实现技术)

十月 18th, {2010 29 条评论 8,426 人阅读过  

离上Openfetion上一个版本发布至今过了有将近一个月的时间了,上个版本放出的时候本以为已经解决了很多bug,但发布之后才发现用户遇到的问题还是很多,软件测试还是很重要的,当然有些协议上的问题只能交由用户去测试,我没有那么多飞信号,有些问题有很难遇到的,也很难复现的,所以就在这样不断地与用户沟通中解决问题。

其实做共享软件是件很开心的事情,不管你做得好不好,都会有人支持你,这个是很重要的,因为在最初开发openfetion的时候并没有想过要把它做为一个专业的飞信客户端放出来大家一起使用,可发布之后得到了广大linux用户的支持,即使那时候的bug比现在多得多,仍然有用户乐此不彼地帮我测试,反溃问题,提供建议,当然我也乐此不彼地修改程序,希望有朝一日它能让所有的用户都能稳定地运行,这也是自由软件的优势,如果当初这做为一个商业软件发布,我想毫无疑问,收到的会是一片骂声,然后这个项目也便会匆匆截止,而现在即便很忙也会拿出一些时间来加强它,因为总会有用户支持着它,也会有开源爱好者加入进来做一些贡献。

Openfetion下一个的版本号应该是2.0了,我想2.0应该和之前的1.x版本有所区别,功能上这个不是特别重要,因为之前的版本已经有了几乎所有的基本功能,其它的一些不常用的功能我也没考虑过,因为开发那些功能是一件性价比很低的事情,现在所能想到的2.0和1.x的区别应该是让2.0更加稳定,功能再丰富如果不能稳定运行这个软件就永远成不了优秀的软件,因为我在新版本里面做了大批量的代码修改,甚至包括以前一些很不专业的编码习惯,尽可能将所有潜在的问题都消灭掉,当然也加了一些用户一直以来要求的功能,下面简单地说一下。

首先,是在之前版本中,用户反映登录速度过慢,这个我承认,是因为在之前的版本中没有加入数据的本地缓存,每次用户登录的时候都会需要重新从服务器上请求自己相关的所有数据,包括用户列表和配置文件这样庞大到几个K甚至十几个K的数据,这不可避免地会导致登录过程过慢,甚至网络状况不好的时候,会导致在获取配置文件的时候卡在那里,这些问题都降低了用户体验,解决这些问题的方法毫无疑问是加入本地用户缓存,这也是网络软件所常用的方式,之前我把一些本地配置信息和聊天记录保存在本地所用的方法是直接使用二进制写入dat文件,那种方法灵活性非常差,而且效率也很低,所有就没有对其它的动态数据做缓存,现在在新版本中引用了sqlite3,这个轻量级的数据库无疑是实现这个功能的绝佳选择,使用起来很简单,而且灵活性也很高,基本的SQL语句几乎都支持,之前只是知道有这么个东西,但一直没用过,这次试了一下,发现使用起来也非常简单,于是毫不犹豫就把它给引入了,我想加入了这样一个依赖所带来的用户体验的提高是很大的,希望不会有用户抱怨引赖关系增多。

另外,在将数据进行本地缓存之后便为另一个功能的实现提供了基础,那就是离线登录功能,和IM的离线功能一样,就是在没有网络连接的情况下登录Openfetion,可以查看好友列表,当然这些好友信息都是存储在本地数据中的,通过sqlite3从数据库中提取出来的。

聊天记录改用sqlite3存储之后提取和写入也都方便了很多,而且还添加了删除聊天记录的功能,之前用二进制数据直接写入的方式保存聊天记录所带来的不便就是不能方便地删除聊天记录,如果要删除只能先把整个聊天记录都加载到内存中,然后从中删掉要删除的信息,之后再重新写入磁盘覆盖掉原来的文件,这样效率是非常低的,而用sqlite3直接可以用一条DELETE语句删掉想要删除的信息。

同样这次也加入了本地用户列表删除功能,用户登录完后记录在本地的用户名密码数据也同样都可以删除。

另一个很重要的功能是空闲时间自动离开功能,这个功能之前一直不知道该怎么实现,纠结于当焦点不在Openfetion中时,如何获取全局的鼠标键盘动作,而即便获取到了又如何检测是否空闲,这些问题都非常麻烦,后来查看了一下pidgin的源码,才发现其实IM软件所实现的空闲时间检测功能一般都是通过调用XScreenSaver来实现的,包括之前的evaqq也是之样实现的,过程很简单,下面的几行代码便是获取空闲时间的函数,通过周期性地检测空闲时间便可以判断出IM是否需要进行离开状态。

gint idle_timesec(void)
{
 
#ifdef USE_LIBXSS
	static XScreenSaverInfo *mit_info = NULL;
	static gint has_extension = -1;
	gint event_base, error_base;
 
	if (has_extension == -1)
		has_extension = XScreenSaverQueryExtension(
				GDK_DISPLAY(), &event_base, &error_base);
 
	if(has_extension){
		if (mit_info == NULL)
			mit_info = XScreenSaverAllocInfo();
 
		XScreenSaverQueryInfo(GDK_DISPLAY(), GDK_ROOT_WINDOW(), mit_info);
		return (mit_info->idle)/1000;
	}
#endif
	return 0;
}

这需要XScreenSaver的支持才行,于是加入了条件编译,在ubuntu或者debian中可以通过下面的命令安装XScreenSaver开发包:

sudo apt-get install libxss-dev

另外一个很重要的功能是断线自动离开功能,这个用tcp的相关特性来检测链路状态灵敏性太低,参考了一下pidgin和empathy,它们用的方法都是调用NetworkManager的相关API来实现的,NetworkManager是基于dbus的,之前在slackware13.1上因为安装NetworkManager失败,而导致之前同学写的基于nm和dbus的程序在我这里不能跑,从而对这个一直留有某种恐惧感,当然现在也意识到要让程序在网络状态改变的时候即刻感知到,最佳方法还是使用libnm,下面的函数便是初始化libnm的函数,它为网络状态改变的事件注册了回调函数nm_state_change()

void fx_conn_init(FxMain *fxmain)
{
#ifdef USE_NETWORKMANAGER
	GError *error = NULL;
        DBusGConnection *nm_conn = NULL;
        DBusGProxy *nm_proxy = NULL;
 
	nm_conn = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
	if (!nm_conn) {
		debug_error("Error connecting to DBus System service: %s.\n", error->message);
	} else {
		nm_proxy = dbus_g_proxy_new_for_name(nm_conn,
		                                     NM_DBUS_SERVICE,
		                                     NM_DBUS_PATH,
		                                     NM_DBUS_INTERFACE);
		dbus_g_proxy_add_signal(nm_proxy, "StateChange", G_TYPE_UINT, G_TYPE_INVALID);
		dbus_g_proxy_connect_signal(nm_proxy, "StateChange",
		                        G_CALLBACK(nm_state_change), fxmain, NULL);
	}
#endif
}

下面的代码是回调函数的代码,在它里面能过检测各种网络状态而做出相应的动作:

static void
nm_state_change(DBusGProxy *proxy, NMState state, gpointer data)
{
	switch(state)
	{
		case NM_STATE_CONNECTED:
			debug_info("network is connected");
			break;
		case NM_STATE_ASLEEP:
			debug_info("network is sleeping...");
			break;
		case NM_STATE_CONNECTING:
			debug_info("network is connecting...");
			break;
		case NM_STATE_DISCONNECTED:
			debug_info("network is disconnected");
			break;
		case NM_STATE_UNKNOWN:
			debug_info("unknown network state");
		default:
			break;
	}
}

ubuntu或debian中NetworkManager开发包的安装方法如下:

sudo apt-get install libnm-glib-deb

要说的是,XScreenSaver和NetworkManager的使用都是可选项,为了避免不愿意引入这些库的用户抱怨,可以在configure的时候用–disable-screensaver和–disable-nm将其禁用。

另外也解决几个崩溃的bug,比如添加好友时崩溃,这个纯粹是我编码过程中出现的失误,还有群发短信时崩溃的问题,这个也是我编码的失误,都已经修改过来了,有时候收到的信息会显示发送失败,这个也修改好了,一个比较重要的bug是多人同时聊天在窗口切换的时候可能会崩溃的问题,这个问题现在也已经解决了。

有时候程序会出现 ”Program received signal SIGPIPE, Broken pipe.“这样的错误,这个信号一般是在服务器端主动关闭连接时客户端会收到的来自操作系统的信号,理论上服务器端主动关闭连接这个可能性不大,但它有时候确实会出现,之前没有对这个信号进行处理,这次把这个信号直接忽略了,然后在send和recv的时候就会返回-1,通过返回值就可以检测连接状态。

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

还有用户提到在登录时登录按钮状态不变,这个之前没怎么在意,这次也修改过来了,不过没有加取消登录的功能,这个也考虑过,不过没想到实现的方法,因为登录线程用的是gthread库,而它没有像pthread一样提供取消线程的方法,一时间也不知道该怎么去实现,这个先暂时一放,希望有了解这个的朋友可以提供些帮助,现在的实现方法是像官方飞信一样在点击登录后改变登录界面,自己还用GIMP做了个登录正在进行的gif,就是让Openfetion的图标一直在转,哈哈,很有成就感,上两个登录界面的图吧。

image image

图片里面没有打码,这个飞信号是我测试用的小号,无所谓了,反正也不用。

这次新版本想多测试一段时间再发,肯定还存在问题,尽可能在发布之前能解决更多的问题,能让2.0正式版更稳定,能让用户更满意,同时也欢迎大家到svn上co最新的版本试用,并帮忙测试,如果你有问题,请向我反溃,这样我才能帮你解决问题。svn :

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

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

印象杭州

十月 9th, {2010 14 条评论 9,928 人阅读过  

近日因出行杭州而导致博客疏于管理,很多网友留言都未能一一回复,恳请见谅。

十几个小时旅途奔波终于活着回到了北邮校园,杭州一行搞得我疲惫不堪,我讨厌旅游,如果不是小卉非要跑到离我1600Km的地方去读书,我宁愿在这个漫漫的十一长假里面好好享受待在宿舍里睡觉的乐趣,第一次选在这种旅游高峰期出行,也因此体会到了我泱泱大国庞大的人口压力。

第一次去杭州,很早以前就想去一次,因为五年前想去浙大读计算机,结果却沦落到青岛混过了四年,也因为小卉在那里,它也因此一度成为我未来工作生活的备选地之一,这次也算是去做一个实地考察,不过结果却着实令我失望。

一下火车给我的第一感觉是来到了济南,不过也还好,济南怎么说也是山东的省会,而且火车站这种地方本来就比较复杂,也无可厚非。但最让我不爽的是这里的风土人情,一下火车便跟公交车司机吵了一架,那人一脸的傲慢,而且还出言不逊,让我想不明白是区区一个公交车司机到底有什么了不起的?后来我慢慢明白了,杭州中下层的人民普遍都会觉得自己很了不起,当然上层人和有文化的人我没机会接触,特别是服务业餐饮业,从业人员态度都极其恶劣,言语表情中都透露着一种不屑,仿佛是回到了计划经济时代,业主都是上帝,顾客都他妈的是孙子。唯一收到笑脸的地方是服装店,各家都是一如既往地热情,所到之处无异。

其实并不是对这座城市的全盘否定,只是感觉杭州缺少一种大城市所应有的气度,当然这也有可能是南北方文化的差异,撇开政治不谈,有了这样的对比,才会感觉到北京作为一个国际大都市在风土民情方面所展现出的气度,北京毕竟是国家的首都,人们的基本素质相比之下还是会稍微高一个层次,至少在北京生活的这段时间没有受到别人冷眼相待,特别是像我这种重度路痴需要时常问路的人,也可以很轻松地在各个节点找到自己的路由矢量,这一点青岛也不及北京,普通大众还是缺乏最基本的礼貌和素质。

如果再说到居住环境,那杭州应该还是要高一个档次的,撇开像火车站等那些复杂的地区不说,杭州虽然没能给人一种现代的感觉,甚至有些地方像八九十年代的长安街,但它朴素的城市格局也给人几分淡然,也可能是因为我住在西湖附近,周围尽是一片绿色,抛开人文因素不谈,走在那里还是会有一种舒畅的感觉,虽然已不是荷花盛开的季节,但竹林荷叶也不失为一种美景,对西湖整体没什么印象,只有曲院风荷和西湖的音乐喷泉感觉还很不错。我们两人游玩总是会选择最经济的路径,需要门票的景点轻易不去,并非收费景点才是值得看的景点,在我看来恰恰相反,什么某某顾居某某别院有什么好看的,那我死后是不是也可以让我儿子在我家门口设个收费点,大家过来参观一下我吃饭的锅,睡觉的床啊。

在浙大待的时间比较长,有时候挺羡慕在这些高等学府里面读书的人,虽然我现在也在北京读书,但北邮还是没有清华北大那种博大的气势,当然这也并非重点,在中国读书基本上都是一回事了,教育体制如此,我们又何以要求太多,大家都懂得,为防止博客出事,过激的言论我避开不谈,也不是我写这个的重点。

借此探望女友之际小游了一下杭州,总体来说,我对这座城市已然兴趣阑珊,一方面它最鲜明的特性是一座旅游城市,在科技等方面虽然相比之青岛略省几畴,但发展空间较之北京还是太小,另一方面杭州高房价甚于北京,即便我对房子这方面的人生观早就开始转变,但要让女友和她家人的观点也随之转变不是那么简单,再者便是刚才提到的风土民情。

声明,以上只是我个人所见所想,并无全盘否定杭州之意,也并无针对杭州人之意。

分类: My Life 标签: