Archive for the ‘科技’ Category

摄像机CCD芯片与DSP类型(转帖)

星期二, 十二月 7th, 2010

关于摄像机的分辨率,

分辨率的定义是在影像像素的基础上的,如下所示:

1)影像像素在25万像素(pixel)左右、彩色分辨率为330线、黑白分辨率400线左右的低档型。

2)影像像素在25-38万像素左右、彩色分辨率为420线、黑白分辨率500线左右的中档型。

3)影像像素在25万像素左右、彩色分辨率为480线、黑白分辨率600线左右的高档型。

摄像机参数标得越来越玄糊,决定探究竟:

CCD的结构为三层,第一层是“微型镜头”,第二层是“分色滤色片”以及第三层“感光层”。

Super HAD CCD中文就是超级HAD CCD传感器,增加了聚光镜头,比普通CCD效果大有改善。

Sony Super Had Ⅱ CCD感度提升了136%,同时噪点更低。多用于低照度枪机。

CCD 名称 CCD 型号 CCD 尺寸 CCD感度
Super HAD II ICX639AK 1/3″ 2250
Super HAD ICX409AK 1/3″ 950
Exview ICX259AK 1/3″ 1100

目前Super HAD CCD是各品牌使用最多的CCD:如405,409

SONY Super HAD II CCD芯片分别为ICX633,ICX639

DSP: 3172 3142 4103 日立93118

EXview 255 259

EX-View:是索尼公司研发用来提高其CCD感光度的一个感光度提高技术,一是两个可见光的因素,二是四倍近红外波的波长。

Vertical double-density interline CCD 213AK

采用CCD+DSP芯片的识别方法:

3142+405 420TVL 经济适用

3142+633 420TVL 刚出来的CCD,用的厂家比较少,照度很低,但是偏色的严重(我所看过的)

2163+405 480TVL(所谓假高线) 性价比高,照度低适合装红外机

2163+409 480TVL 照度高不适合装红外机,适合普通枪机半球

4103+405 480TVL(所谓假高线) 性价比高,照度低适合装红外机

4103+409 480TVL(传说的520TVL)照度高不适合装红外机,效果一般

4103+639 480TVL(传说的540TVL)照度还可以,适合装红外机.

3172+639 480TVL(传说的540TVL)

2163+255 420TVL 低线低照,用的少不做评论

2163+529 480TVL 高线低照,用的少不做评论

633是以后代替405的,他灵敏度比405高上很多,如果技术到位做出来的照度会非常低,装红外效果不错

639是以后代替409的.灵敏度大大高过409,如果技术到位,将弥补市场上高线红外机效果差这一缺陷.

在相同参数下,感觉3172+409白天的色彩比较鲜艳一点。3172+639白天的色彩有点偏兰。而3172+409在晚上没有红外灯时,噪点比较大。3172+639在晚上没有红外灯时,噪点比较小,比3172+409的照度好一点.

639与409的主要差别,在于639的赶度提高了(约等于以前的405),其余的639跟409差不多。
问题在于:
1.感度提高了,好处在低照状况下,效果比409好多了,也就是夜视效果比较好。
2.但感度提高了,相当于入光量变大了,在不改参数的情况下,颜色就会变淡。
3.前端那颗 3796(CDS/AGC,取代原来的2096),如果只是用原来的2096参数,效果也不好
所以,如果用639取代409,照度变好了,但dsp参数得修改,连色矩阵的运算都得调整过,才能有409的彩色效果,不是把CCD换掉就行了。可惜,这几年来,会调DSP参数的人越来越少了,还得等一阵子,大家抄来抄去,总会抄出个名堂来的。不管搭3172还是4103都一样。

另外,用633取代405,情况更严重,633其实感度有点太好了,夜视效果非常好,但在大太阳下很容易过曝,掉色更严重,搭3142这颗本来就不好的DSP,想搞好很难,加上这几年都在打价格战,零件都尽量省了,一般板子噪讯都很高,搭上633这高感度的CCD,噪讯问题更严重。但633如果搭3172或4103的话,就好搞多了,只是成本变高,只能当假高线卖了。

632(N制的),更惨,多了个严重色滚,无解,除非加电源同步,但那价格没几个人能接受的
真不知道索尼是怎么想的,可能是为接下来的新DSP做准备的吧。
4103是代替2163的DSP,可不知道为什么,SONY又接着推出了3172.而3172做出来的效果却并不理想.

3172方案效果确实比4103要好一些,不过芯片温度比较高,最高的时候达到近70度,做还是可以做的,第一,做双板.第二,电源要用效率高的,发热量小.第三,最好加散热片.还有一种做法,3172 3.3V上面用2.9V-3.0V去供,哈哈,很多这样搞的噢,要小心

639CCD的DSP可用日立93118的,比3172的要更好

红外一体机选购考虑因素:

1,采用先进的方案:420线一般采用的是3142+633方案,480线一般采用4103+639方案,500线以上我们采用3172+639方案。
2,采用稳定的LED红外灯:我们的红外系列采用的是台湾鼎元的LED红外灯,其寿命长,功率稳定,散热性较好,红外线发射均匀,不易因为电流瞬间过大而烧毁。并且采用“双灯技术”,宽角和窄角红外灯搭配,解决了红外灯角度与距离的互补效果。
3,采用专用IR镜头:红外机因其接受红外线反射原理在夜间成像,因此专用的IR镜头更有利接受红外线,从而夜间成像效果更佳。而我公司选用的IR镜头均为韩国进口镜头,不偏焦。
4,采用双滤光片切换:因红外彩转黑摄像机为了达到夜间接受红外线成像,需要一块特制滤光片,如果共用同一滤光片,那么白天的成像效果不佳,容易造成偏色,采用双滤光片切换可以很好的解决这一问题。
5,采用双玻设计:采用双玻设计可有效避免反光,因此摄像效果更佳。

实际评价与测试:

3142+633BK:夜视效果还可以:

3172+639BK:夜视效果听说还可以:

高线/低线、IC及电流关系:

线 数 IC及CCD配搭 电 流

420TVL 3141(1267、2096)+ 405 120MA

450TVL 2163(2006、2480)+ 405 120MA

480TVL 2163(2006、2480)+ 409 170MA

450TVL 2163(2006、2480)+ 255 170MA(低照度)

480TVL 2163(2006、2480)+ 259 170MA(高线低照度)

有420线(405+3142+2096) 480线(409+2163+2480+2006)

520线(409+3172+2096)

1/3"SONY420线彩色摄象机 D3141+405AK
1/3"SONY460线彩色摄象机 D2163+405AK
1/3"SONY480线彩色摄象机 D2163+409AK
1/3"SONY480线彩色摄象机 D2163+408AK
1/3"SONY535线彩色摄象机 D3172+409AK
1/4"SONY420线彩色半球 D3141+227AK
1/3"SONY420线彩色半球 D3141+405AK
1/3"SONY460线彩色半球 D2163+405AK
1/3"SONY480线彩色半球 D2163+409AK
1/3"SONY600线黑白半球 D2463+409AL

1/4"SONY420线彩色转黑白摄象机(软件转) D3141+227AK
1/3"SONY420线彩色转黑白摄象机(软件转) D3141+405AK
1/3"SONY460线彩色转黑白摄象机(软件转) D2163+405AK
1/3"SONY480线彩色转黑白摄象机(软件转) D2163+409AK
1/3"SONY480线彩色转黑白摄象机N制(软件转) D2163+408AK
1/3"SONY535线彩色转黑白摄象机N制(软件转) D3172+408AK
1/4"SONY420线彩色转黑白半球(软件转) D3141+227AK
1/3"SONY420线彩色转黑白半球(软件转) D3141+405AK
1/3"SONY460线彩色转黑白半球(软件转) D2163+405AK
1/3"SONY480线彩色转黑白半球(软件转) D2163+409AK
1/3"SONY535线彩色转黑白半球(软件转) D3172+409AK
1/3"SONY420线彩色低照度摄象机 D3141+255AK
1/3"SONY460线彩色低照度摄象机 D2163+255AK
1/3"SONY480线彩色低照度摄象机 D2163+259AK
1/3"SONY520线彩色低照度摄象机 D3172+259AK
1/2"SONY535线彩色摄象机 D3172+259AK

Memcached深度分析(转载)

星期三, 九月 1st, 2010

原作网站已经木有了。
------------------------------------------------------------------------------------------

Memcached是danga.com(运营LiveJournal的技术团队)开发的一套分布式内存对象缓存系统,用于在动态系统中减少数据库 负载,提升性能。关于这个东西,相信很多人都用过,本文意在通过对memcached的实现及代码分析,获得对这个出色的开源软件更深入的了解,并可以根 据我们的需要对其进行更进一步的优化。末了将通过对BSM_Memcache扩展的分析,加深对memcached的使用方式理解。

本文的部分内容可能需要比较好的数学基础作为辅助。

◎Memcached是什么

在阐述这个问题之前,我们首先要清楚它“不是什么”。很多人把它当作和SharedMemory那种形式的存储载体来使用,虽然memcached 使用了同样的“Key=>Value”方式组织数据,但是它和共享内存、APC等本地缓存有非常大的区别。Memcached是分布式的,也就是说 它不是本地的。它基于网络连接(当然它也可以使用localhost)方式完成服务,本身它是一个独立于应用的程序或守护进程(Daemon方式)。

Memcached使用libevent库实现网络连接服务,理论上可以处理无限多的连接,但是它和Apache不同,它更多的时候是面向稳定的持 续连接的,所以它实际的并发能力是有限制的。在保守情况下memcached的最大同时连接数为200,这和Linux线程能力有关系,这个数值是可以调 整的。关于libevent可以参考相关文档。 Memcached内存使用方式也和APC不同。APC是基于共享内存和MMAP的,memcachd有自己的内存分配算法和管理方式,它和共享内存没有 关系,也没有共享内存的限制,通常情况下,每个memcached进程可以管理2GB的内存空间,如果需要更多的空间,可以增加进程数。

◎Memcached适合什么场合

在很多时候,memcached都被滥用了,这当然少不了对它的抱怨。我经常在论坛上看见有人发贴,类似于“如何提高效率”,回复是“用 memcached”,至于怎么用,用在哪里,用来干什么一句没有。memcached不是万能的,它也不是适用在所有场合。

Memcached是“分布式”的内存对象缓存系统,那么就是说,那些不需要“分布”的,不需要共享的,或者干脆规模小到只有一台服务器的应 用,memcached不会带来任何好处,相反还会拖慢系统效率,因为网络连接同样需要资源,即使是UNIX本地连接也一样。 在我之前的测试数据中显示,memcached本地读写速度要比直接PHP内存数组慢几十倍,而APC、共享内存方式都和直接数组差不多。可见,如果只是 本地级缓存,使用memcached是非常不划算的。

Memcached在很多时候都是作为数据库前端cache使用的。因为它比数据库少了很多SQL解析、磁盘操作等开销,而且它是使用内存来管理数 据的,所以它可以提供比直接读取数据库更好的性能,在大型系统中,访问同样的数据是很频繁的,memcached可以大大降低数据库压力,使系统执行效率 提升。另外,memcached也经常作为服务器之间数据共享的存储媒介,例如在SSO系统中保存系统单点登陆状态的数据就可以保存在memcached 中,被多个应用共享。

需要注意的是,memcached使用内存管理数据,所以它是易失的,当服务器重启,或者memcached进程中止,数据便会丢失,所以 memcached不能用来持久保存数据。很多人的错误理解,memcached的性能非常好,好到了内存和硬盘的对比程度,其实memcached使用 内存并不会得到成百上千的读写速度提高,它的实际瓶颈在于网络连接,它和使用磁盘的数据库系统相比,好处在于它本身非常“轻”,因为没有过多的开销和直接 的读写方式,它可以轻松应付非常大的数据交换量,所以经常会出现两条千兆网络带宽都满负荷了,memcached进程本身并不占用多少CPU资源的情况。

◎Memcached的工作方式

以下的部分中,读者最好能准备一份memcached的源代码。

Memcached是传统的网络服务程序,如果启动的时候使用了-d参数,它会以守护进程的方式执行。创建守护进程由daemon.c完成,这个程 序只有一个daemon函数,这个函数很简单(如无特殊说明,代码以1.2.1为准):

CODE:
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>int
daemon(nochdir, noclose)
int nochdir, noclose;
{
int fd;

switch (fork()) {
case -1:
return (-1);
case 0:
break;
default:
_exit(0);
}

if (setsid() == -1)
return (-1);

if (!nochdir)
(void)chdir(”/”);

if (!noclose && (fd = open(”/dev/null”, O_RDWR, 0)) != -1) {
(void)dup2(fd, STDIN_FILENO);
(void)dup2(fd, STDOUT_FILENO);
(void)dup2(fd, STDERR_FILENO);
if (fd > STDERR_FILENO)
(void)close(fd);
}
return (0);
}

这个函数 fork 了整个进程之后,父进程就退出,接着重新定位 STDIN 、 STDOUT 、 STDERR 到空设备, daemon 就建立成功了。

Memcached 本身的启动过程,在 memcached.c 的 main 函数中顺序如下:

1 、调用 settings_init() 设定初始化参数
2 、从启动命令中读取参数来设置 setting 值
3 、设定 LIMIT 参数
4 、开始网络 socket 监听(如果非 socketpath 存在)( 1.2 之后支持 UDP 方式)
5 、检查用户身份( Memcached 不允许 root 身份启动)
6 、如果有 socketpath 存在,开启 UNIX 本地连接(Sock 管道)
7 、如果以 -d 方式启动,创建守护进程(如上调用 daemon 函数)
8 、初始化 item 、 event 、状态信息、 hash 、连接、 slab
9 、如设置中 managed 生效,创建 bucket 数组
10 、检查是否需要锁定内存页
11 、初始化信号、连接、删除队列
12 、如果 daemon 方式,处理进程 ID
13 、event 开始,启动过程结束, main 函数进入循环。

在 daemon 方式中,因为 stderr 已经被定向到黑洞,所以不会反馈执行中的可见错误信息。

memcached.c 的主循环函数是 drive_machine ,传入参数是指向当前的连接的结构指针,根据 state 成员的状态来决定动作。

Memcached 使用一套自定义的协议完成数据交换,它的 protocol 文档可以参考: http://code.sixapart.com/svn/memcached/trunk/server/doc/protocol.txt

在API中,换行符号统一为\r\n

◎Memcached的内存管理方式

Memcached有一个很有特色的内存管理方式,为了提高效率,它使用预申请和分组的方式管理内存空间,而并不是每次需要写入数据的时候去 malloc,删除数据的时候free一个指针。Memcached使用slab->chunk的组织方式管理内存。

1.1和1.2的slabs.c中的slab空间划分算法有一些不同,后面会分别介绍。

Slab可以理解为一个内存块,一个slab是memcached一次申请内存的最小单位,在memcached中,一个slab的大小默认为 1048576字节(1MB),所以memcached都是整MB的使用内存。每一个slab被划分为若干个chunk,每个chunk里保存一个 item,每个item同时包含了item结构体、key和value(注意在memcached中的value是只有字符串的)。slab按照自己的 id分别组成链表,这些链表又按id挂在一个slabclass数组上,整个结构看起来有点像二维数组。slabclass的长度在1.1中是21,在 1.2中是200。

slab有一个初始chunk大小,1.1中是1字节,1.2中是80字节,1.2中有一个factor值,默认为1.25

在1.1中,chunk大小表示为初始大小*2^n,n为classid,即:id为0的slab,每chunk大小1字节,id为1的slab, 每chunk大小2字节,id为2的slab,每chunk大小4字节……id为20的slab,每chunk大小为1MB,就是说id为20的slab 里只有一个chunk:

CODE:
void slabs_init(size_t limit) {
int i;
int size=1;mem_limit = limit;
for(i=0; i<=POWER_LARGEST; i++, size*=2) {
slabclass[i].size = size;
slabclass[i].perslab = POWER_BLOCK / size;
slabclass[i].slots = 0;
slabclass[i].sl_curr = slabclass[i].sl_total = slabclass[i].slabs = 0;
slabclass[i].end_page_ptr = 0;
slabclass[i].end_page_free = 0;
slabclass[i].slab_list = 0;
slabclass[i].list_size = 0;
slabclass[i].killing = 0;
}

/* for the test suite:  faking of how much we’ve already malloc’d */
{
char *t_initial_malloc = getenv(”T_MEMD_INITIAL_MALLOC”);
if (t_initial_malloc) {
mem_malloced = atol(getenv(”T_MEMD_INITIAL_MALLOC”));
}
}

/* pre-allocate slabs by default, unless the environment variable
for testing is set to something non-zero */
{
char *pre_alloc = getenv(”T_MEMD_SLABS_ALLOC”);
if (!pre_alloc || atoi(pre_alloc)) {
slabs_preallocate(limit / POWER_BLOCK);
}
}
}

在1.2中,chunk大小表示为初始大小*f^n,f为factor,在memcached.c中定义,n为classid,同时,201个头不 是全部都要初始化的,因为factor可变,初始化只循环到计算出的大小达到slab大小的一半为止,而且它是从id1开始的,即:id为1的slab, 每chunk大小80字节,id为2的slab,每chunk大小80*f,id为3的slab,每chunk大小80*f^2,初始化大小有一个修正值 CHUNK_ALIGN_BYTES,用来保证n-byte排列 (保证结果是CHUNK_ALIGN_BYTES的整倍数)。这样,在标准情况下,memcached1.2会初始化到id40,这个slab中每个 chunk大小为504692,每个slab中有两个chunk。最后,slab_init函数会在最后补足一个id41,它是整块的,也就是这个 slab中只有一个1MB大的chunk:

CODE:
void slabs_init(size_t limit, double factor) {
int i = POWER_SMALLEST – 1;
unsigned int size = sizeof(item) + settings.chunk_size;/* Factor of 2.0 means use the default memcached behavior */
if (factor == 2.0 && size < 128)
size = 128;

mem_limit = limit;
memset(slabclass, 0, sizeof(slabclass));

while (++i < POWER_LARGEST && size <= POWER_BLOCK / 2) {
/* Make sure items are always n-byte aligned */
if (size % CHUNK_ALIGN_BYTES)
size += CHUNK_ALIGN_BYTES – (size % CHUNK_ALIGN_BYTES);

slabclass[i].size = size;
slabclass[i].perslab = POWER_BLOCK / slabclass[i].size;
size *= factor;
if (settings.verbose > 1) {
fprintf(stderr, “slab class %3d: chunk size %6d perslab %5d\n”,
i, slabclass[i].size, slabclass[i].perslab);
}
}

power_largest = i;
slabclass[power_largest].size = POWER_BLOCK;
slabclass[power_largest].perslab = 1;

/* for the test suite:  faking of how much we’ve already malloc’d */
{
char *t_initial_malloc = getenv(”T_MEMD_INITIAL_MALLOC”);
if (t_initial_malloc) {
mem_malloced = atol(getenv(”T_MEMD_INITIAL_MALLOC”));
}

}

#ifndef DONT_PREALLOC_SLABS
{
char *pre_alloc = getenv(”T_MEMD_SLABS_ALLOC”);
if (!pre_alloc || atoi(pre_alloc)) {
slabs_preallocate(limit / POWER_BLOCK);
}
}
#endif
}

由上可以看出,memcached的内存分配是有冗余的,当一个slab不能被它所拥有的chunk大小整除时,slab尾部剩余的空间就被丢弃 了,如id40中,两个chunk占用了1009384字节,这个slab一共有1MB,那么就有39192字节被浪费了。

Memcached使用这种方式来分配内存,是为了可以快速的通过item长度定位出slab的classid,有一点类似hash,因为item 的长度是可以计算的,比如一个item的长度是300字节,在1.2中就可以得到它应该保存在id7的slab中,因为按照上面的计算方法,id6的 chunk大小是252字节,id7的chunk大小是316字节,id8的chunk大小是396字节,表示所有252到316字节的item都应该保 存在id7中。同理,在1.1中,也可以计算得到它出于256和512之间,应该放在chunk_size为512的id9中(32位系统)。

Memcached初始化的时候,会初始化slab(前面可以看到,在main函数中调用了slabs_init())。它会在 slabs_init()中检查一个常量DONT_PREALLOC_SLABS,如果这个没有被定义,说明使用预分配内存方式初始化slab,这样在所 有已经定义过的slabclass中,每一个id创建一个slab。这样就表示,1.2在默认的环境中启动进程后要分配41MB的slab空间,在这个过 程里,memcached的第二个内存冗余发生了,因为有可能一个id根本没有被使用过,但是它也默认申请了一个slab,每个slab会用掉1MB内存

当一个slab用光后,又有新的item要插入这个id,那么它就会重新申请新的slab,申请新的slab时,对应id的slab链表就要增长, 这个链表是成倍增长的,在函数grow_slab_list函数中,这个链的长度从1变成2,从2变成4,从4变成8……:

CODE:
static int grow_slab_list (unsigned int id) {
slabclass_t *p = &slabclass[id];
if (p->slabs == p->list_size) {
size_t new_size =  p->list_size ? p->list_size * 2 : 16;
void *new_list = realloc(p->slab_list, new_size*sizeof(void*));
if (new_list == 0) return 0;
p->list_size = new_size;
p->slab_list = new_list;
}
return 1;
}

在定位item时,都是使用slabs_clsid函数,传入参数为item大小,返回值为classid,由这个过程可以看 出,memcached的第三个内存冗余发生在保存item的过程中,item总是小于或等于chunk大小的,当item小于chunk大小时,就又发 生了空间浪费。

◎Memcached的NewHash算法

Memcached的item保存基于一个大的hash表,它的实际地址就是slab中的chunk偏移,但是它的定位是依靠对key做hash的 结果,在primary_hashtable中找到的。在assoc.c和items.c中定义了所有的hash和item操作。

Memcached使用了一个叫做NewHash的算法,它的效果很好,效率也很高。1.1和1.2的NewHash有一些不同,主要的实现方式还 是一样的,1.2的hash函数是经过整理优化的,适应性更好一些。

NewHash的原型参考:http://burtleburtle.net/bob/hash/evahash.html。数学家总是有点奇怪, 呵呵~

为了变换方便,定义了u4和u1两种数据类型,u4就是无符号的长整形,u1就是无符号char(0-255)。

具体代码可以参考1.1和1.2源码包。

注意这里的hashtable长度,1.1和1.2也是有区别的,1.1中定义了HASHPOWER常量为20,hashtable表长为 hashsize(HASHPOWER),就是4MB(hashsize是一个宏,表示1右移n位),1.2中是变量16,即hashtable表长 65536:

CODE:
typedef  unsigned long  int  ub4;   /* unsigned 4-byte quantities */
typedef  unsigned       char ub1;   /* unsigned 1-byte quantities */#define hashsize(n) ((ub4)1<<(n))
#define hashmask(n) (hashsize(n)-1)

在assoc_init()中,会对primary_hashtable做初始化,对应的hash操作包括:assoc_find()、 assoc_expand()、assoc_move_next_bucket()、assoc_insert()、assoc_delete(),对应 于item的读写操作。其中assoc_find()是根据key和key长寻找对应的item地址的函数(注意在C中,很多时候都是同时直接传入字符串 和字符串长度,而不是在函数内部做strlen),返回的是item结构指针,它的数据地址在slab中的某个chunk上。

items.c是数据项的操作程序,每一个完整的item包括几个部分,在item_make_header()中定义为:

key:键
nkey:键长
flags:用户定义的flag(其实这个flag在memcached中没有启用)
nbytes:值长(包括换行符号\r\n)
suffix:后缀Buffer
nsuffix:后缀长

一个完整的item长度是键长+值长+后缀长+item结构大小(32字节),item操作就是根据这个长度来计算slab的classid的。

hashtable中的每一个桶上挂着一个双链表,item_init()的时候已经初始化了heads、tails、sizes三个数组为0,这 三个数组的大小都为常量LARGEST_ID(默认为255,这个值需要配合factor来修改),在每次item_assoc()的时候,它会首先尝试 从slab中获取一块空闲的chunk,如果没有可用的chunk,会在链表中扫描50次,以得到一个被LRU踢掉的item,将它unlink,然后将 需要插入的item插入链表中。

注意item的refcount成员。item被unlink之后只是从链表上摘掉,不是立刻就被free的,只是将它放到删除队列中 (item_unlink_q()函数)。

item对应一些读写操作,包括remove、update、replace,当然最重要的就是alloc操作。

item还有一个特性就是它有过期时间,这是memcached的一个很有用的特性,很多应用都是依赖于memcached的item过期,比如 session存储、操作锁等。item_flush_expired()函数就是扫描表中的item,对过期的item执行unlink操作,当然这只 是一个回收动作,实际上在get的时候还要进行时间判断:

CODE:
/* expires items that are more recent than the oldest_live setting. */
void item_flush_expired() {
int i;
item *iter, *next;
if (! settings.oldest_live)
return;
for (i = 0; i < LARGEST_ID; i++) {
/* The LRU is sorted in decreasing time order, and an item’s timestamp
* is never newer than its last access time, so we only need to walk
* back until we hit an item older than the oldest_live time.
* The oldest_live checking will auto-expire the remaining items.
*/
for (iter = heads[i]; iter != NULL; iter = next) {
if (iter->time >= settings.oldest_live) {
next = iter->next;
if ((iter->it_flags & ITEM_SLABBED) == 0) {
item_unlink(iter);
}
} else {
/* We’ve hit the first old item. Continue to the next queue. */
break;
}
}
}
}
CODE:
/* wrapper around assoc_find which does the lazy expiration/deletion logic */
item *get_item_notedeleted(char *key, size_t nkey, int *delete_locked) {
item *it = assoc_find(key, nkey);
if (delete_locked) *delete_locked = 0;
if (it && (it->it_flags & ITEM_DELETED)) {
/* it’s flagged as delete-locked.  let’s see if that condition
is past due, and the 5-second delete_timer just hasn’t
gotten to it yet… */
if (! item_delete_lock_over(it)) {
if (delete_locked) *delete_locked = 1;
it = 0;
}
}
if (it && settings.oldest_live && settings.oldest_live <= current_time &&
it->time <= settings.oldest_live) {
item_unlink(it);
it = 0;
}
if (it && it->exptime && it->exptime <= current_time) {
item_unlink(it);
it = 0;
}
return it;
}

Memcached的内存管理方式是非常精巧和高效的,它很大程度上减少了直接alloc系统内存的次数,降低函数开销和内存碎片产生几率,虽然这 种方式会造成一些冗余浪费,但是这种浪费在大型系统应用中是微不足道的。

◎Memcached的理论参数计算方式

影响 memcached 工作的几个参数有:

常量REALTIME_MAXDELTA 60*60*24*30
最大30天的过期时间

conn_init()中的freetotal(=200)
最大同时连接数

常量KEY_MAX_LENGTH 250
最大键长

settings.factor(=1.25)
factor将影响chunk的步进大小

settings.maxconns(=1024)
最大软连接

settings.chunk_size(=48)
一个保守估计的key+value长度,用来生成id1中的chunk长度(1.2)。id1的chunk长度等于这个数值加上item结构体的长度 (32),即默认的80字节。

常量POWER_SMALLEST 1
最小classid(1.2)

常量POWER_LARGEST 200
最大classid(1.2)

常量POWER_BLOCK 1048576
默认slab大小

常量CHUNK_ALIGN_BYTES (sizeof(void *))
保证chunk大小是这个数值的整数倍,防止越界(void *的长度在不同系统上不一样,在标准32位系统上是4)

常量ITEM_UPDATE_INTERVAL 60
队列刷新间隔

常量LARGEST_ID 255
最大item链表数(这个值不能比最大的classid小)

变量hashpower(在1.1中是常量HASHPOWER)
决定hashtable的大小

根据上面介绍的内容及参数设定,可以计算出的一些结果:

1、在memcached中可以保存的item个数是没有软件上限的,之前我的100万的说法是错误的。
2、假设NewHash算法碰撞均匀,查找item的循环次数是item总数除以hashtable大小(由hashpower决定),是线性的。
3、Memcached限制了可以接受的最大item是1MB,大于1MB的数据不予理会。
4、Memcached的空间利用率和数据特性有很大的关系,又与DONT_PREALLOC_SLABS常量有关。 在最差情况下,有198个slab会被浪费(所有item都集中在一个slab中,199个id全部分配满)。

◎Memcached的定长优化

根据上面几节的描述,多少对memcached有了一个比较深入的认识。在深入认识的基础上才好对它进行优化。

Memcached本身是为变长数据设计的,根据数据特性,可以说它是“面向大众”的设计,但是很多时候,我们的数据并不是这样的“普遍”,典型的 情况中,一种是非均匀分布,即数据长度集中在几个区域内(如保存用户 Session);另一种更极端的状态是等长数据(如定长键值,定长数据,多见于访问、在线统计或执行锁)。

这里主要研究一下定长数据的优化方案(1.2),集中分布的变长数据仅供参考,实现起来也很容易。

解决定长数据,首先需要解决的是slab的分配问题,第一个需要确认的是我们不需要那么多不同chunk长度的slab,为了最大限度地利用资源, 最好chunk和item等长,所以首先要计算item长度。

在之前已经有了计算item长度的算法,需要注意的是,除了字符串长度外,还要加上item结构的长度32字节。

假设我们已经计算出需要保存200字节的等长数据。

接下来是要修改slab的classid和chunk长度的关系。在原始版本中,chunk长度和classid是有对应关系的,现在如果把所有的 chunk都定为200个字节,那么这个关系就不存在了,我们需要重新确定这二者的关系。一种方法是,整个存储结构只使用一个固定的id,即只使用199 个槽中的1个,在这种条件下,就一定要定义DONT_PREALLOC_SLABS来避免另外的预分配浪费。另一种方法是建立一个hash关系,来从 item确定classid,不能使用长度来做键,可以使用key的NewHash结果等不定数据,或者直接根据key来做hash(定长数据的key也 一定等长)。这里简单起见,选择第一种方法,这种方法的不足之处在于只使用一个id,在数据量非常大的情况下,slab链会很长(因为所有数据都挤在一条 链上了),遍历起来的代价比较高。

前面介绍了三种空间冗余,设置chunk长度等于item长度,解决了第一种空间浪费问题,不预申请空间解决了第二种空间浪费问题,那么对于第一种 问题(slab内剩余)如何解决呢,这就需要修改POWER_BLOCK常量,使得每一个slab大小正好等于chunk长度的整数倍,这样一个slab 就可以正好划分成n个chunk。这个数值应该比较接近1MB,过大的话同样会造成冗余,过小的话会造成次数过多的alloc,根据chunk长度为 200,选择1000000作为POWER_BLOCK的值,这样一个slab就是100万字节,不是1048576。三个冗余问题都解决了,空间利用率 会大大提升。

修改 slabs_clsid 函数,让它直接返回一个定值(比如 1 ):

CODE:
unsigned int slabs_clsid(size_t size) {
return 1;
}

修改slabs_init函数,去掉循环创建所有classid属性的部分,直接添加slabclass[1]:

CODE:
slabclass[1].size = 200;                //每chunk200字节
slabclass[1].perslab = 5000;        //1000000/200

◎Memcached客户端

Memcached是一个服务程序,使用的时候可以根据它的协议,连接到memcached服务器上,发送命令给服务进程,就可以操作上面的数据。 为了方便使用,memcached有很多个客户端程序可以使用,对应于各种语言,有各种语言的客户端。基于C语言的有libmemcache、 APR_Memcache;基于Perl的有Cache::Memcached;另外还有Python、Ruby、Java、C#等语言的支持。PHP的 客户端是最多的,不光有mcache和PECL memcache两个扩展,还有大把的由PHP编写的封装类,下面介绍一下在PHP中使用memcached的方法:

mcache扩展是基于libmemcache再封装的。libmemcache一直没有发布stable版本,目前版本是1.4.0-rc2,可 以在这里找到。libmemcache有一个很不好的特性,就是会向stderr写很多错误信息,一般的,作为lib使用的时候,stderr一般都会被 定向到其它地方,比如Apache的错误日志,而且libmemcache会自杀,可能会导致异常,不过它的性能还是很好的。

mcache扩展最后更新到1.2.0-beta10,作者大概是离职了,不光停止更新,连网站也打不开了(~_~),只能到其它地方去获取这个不 负责的扩展了。解压后安装方法如常:phpize & configure & make & make install,一定要先安装libmemcache。使用这个扩展很简单:

CODE:
<?php
$mc = memcache();    // 创 建一个memcache连接对象,注意这里不是用new!
$mc->add_server(‘localhost’, 11211);    // 添 加一个服务进程
$mc->add_server(‘localhost’, 11212);    // 添 加第二个服务进程
$mc->set(‘key1′, ‘Hello’);    // 写 入key1 => Hello
$mc->set(‘key2′, ‘World’, 10);    // 写 入key2 => World,10秒过期
$mc->set(‘arr1′, array(‘Hello’, ‘World’));    // 写 入一个数组
$key1 = $mc->get(‘key1′);    // 获 取’key1′的值,赋给$key1
$key2 = $mc->get(‘key2′);    // 获 取’key2′的值,赋给$key2,如果超过10秒,就取不到了
$arr1 = $mc->get(‘arr1′);    // 获 取’arr1′数组
$mc->delete(‘arr1′);    // 删 除’arr1′
$mc->flush_all();    // 删 掉所有数据
$stats = $mc->stats();    // 获 取服务器信息
var_dump($stats);    // 服 务器信息是一个数组
?>

这个扩展的好处是可以很方便地实现分布式存储和负载均衡,因为它可以添加多个服务地址,数据在保存的时候是会根据hash结果定位到某台服务器上 的,这也是libmemcache的特性。libmemcache支持集中hash方式,包括CRC32、ELF和Perl hash。

PECL memcache是PECL发布的扩展,目前最新版本是2.1.0,可以在pecl网站得到。memcache扩展的使用方法可以在新一些的PHP手册中 找到,它和mcache很像,真的很像:

CODE:
<?php$memcache

= new Memcache;
$memcache->connect(‘localhost’, 11211) or die (“Could not connect”);

$version = $memcache->getVersion();
echo “Server’s version: ”.$version.“n”;

$tmp_object = new stdClass;
$tmp_object->str_attr = ‘test’;
$tmp_object->int_attr = 123;

$memcache->set(‘key’, $tmp_object, false, 10) or die (“Failed to save data at the server”);
echo “Store data in the cache (data will expire in 10 seconds)n”;

$get_result = $memcache->get(‘key’);
echo “Data from the cache:n”;

var_dump($get_result);

?>

这个扩展是使用php的stream直接连接memcached服务器并通过socket发送命令的。它不像libmemcache那样完善,也不 支持add_server这种分布操作,但是因为它不依赖其它的外界程序,兼容性要好一些,也比较稳定。至于效率,差别不是很大。

另外,有很多的PHP class可以使用,比如MemcacheClient.inc.php,phpclasses.org上可以找到很多,一般都是对perl client API的再封装,使用方式很像。

◎BSM_Memcache

从C client来说,APR_Memcache是一个很成熟很稳定的client程序,支持线程锁和原子级操作,保证运行的稳定性。不过它是基于APR的 (APR将在最后一节介绍),没有libmemcache的应用范围广,目前也没有很多基于它开发的程序,现有的多是一些Apache Module,因为它不能脱离APR环境运行。但是APR倒是可以脱离Apache单独安装的,在APR网站上可以下载APR和APR-util,不需要 有Apache,可以直接安装,而且它是跨平台的。

BSM_Memcache是我在BS.Magic项目中开发的一个基于APR_Memcache的PHP扩展,说起来有点拗口,至少它把APR扯进 了PHP扩展中。这个程序很简单,也没做太多的功能,只是一种形式的尝试,它支持服务器分组。

和mcache扩展支持多服务器分布存储不同,BSM_Memcache支持多组服务器,每一组内的服务器还是按照hash方式来分布保存数据,但 是两个组中保存的数据是一样的,也就是实现了热备,它不会因为一台服务器发生单点故障导致数据无法获取,除非所有的服务器组都损坏(例如机房停电)。当然 实现这个功能的代价就是性能上的牺牲,在每次添加删除数据的时候都要扫描所有的组,在get数据的时候会随机选择一组服务器开始轮询,一直到找到数据为 止,正常情况下一次就可以获取得到。

BSM_Memcache只支持这几个函数:

CODE:
zend_function_entry bsm_memcache_functions[] =
{
PHP_FE(mc_get,          NULL)
PHP_FE(mc_set,          NULL)
PHP_FE(mc_del,          NULL)
PHP_FE(mc_add_group,    NULL)
PHP_FE(mc_add_server,   NULL)
PHP_FE(mc_shutdown,     NULL)
{NULL, NULL, NULL}
};

mc_add_group函数返回一个整形(其实应该是一个object,我偷懒了~_~)作为组ID,mc_add_server的时候要提供两 个参数,一个是组ID,一个是服务器地址(ADDRORT)。

CODE:
/**
* Add a server group
*/
PHP_FUNCTION(mc_add_group)
{
apr_int32_t group_id;
apr_status_t rv;if (0 != ZEND_NUM_ARGS())
{
WRONG_PARAM_COUNT;
RETURN_NULL();
}

group_id = free_group_id();
if (-1 == group_id)
{
RETURN_FALSE;
}

apr_memcache_t *mc;
rv = apr_memcache_create(p, MAX_G_SERVER, 0, &mc);

add_group(group_id, mc);

RETURN_DOUBLE(group_id);
}

CODE:
/**
* Add a server into group
*/
PHP_FUNCTION(mc_add_server)
{
apr_status_t rv;
apr_int32_t group_id;
double g;
char *srv_str;
int srv_str_l;if (2 != ZEND_NUM_ARGS())
{
WRONG_PARAM_COUNT;
}

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, “ds”, &g, &srv_str, &srv_str_l) == FAILURE)
{
RETURN_FALSE;
}

group_id = (apr_int32_t) g;

if (-1 == is_validate_group(group_id))
{
RETURN_FALSE;
}

char *host, *scope;
apr_port_t port;

rv = apr_parse_addr_port(&host, &scope, &port, srv_str, p);
if (APR_SUCCESS == rv)
{
// Create this server object
apr_memcache_server_t *st;
rv = apr_memcache_server_create(p, host, port, 0, 64, 1024, 600, &st);
if (APR_SUCCESS == rv)
{
if (NULL == mc_groups[group_id])
{
RETURN_FALSE;
}

// Add server
rv = apr_memcache_add_server(mc_groups[group_id], st);

if (APR_SUCCESS == rv)
{
RETURN_TRUE;
}
}
}

RETURN_FALSE;
}

在set和del数据的时候,要循环所有的组:

CODE:
/**
* Store item into all groups
*/
PHP_FUNCTION(mc_set)
{
char *key, *value;
int key_l, value_l;
double ttl = 0;
double set_ct = 0;if (2 != ZEND_NUM_ARGS())
{
WRONG_PARAM_COUNT;
}

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, “ss|d”, &key, &key_l, &value, &value_l, ttl) == FAILURE)
{
RETURN_FALSE;
}

// Write data into every object
apr_int32_t i = 0;
if (ttl < 0)
{
ttl = 0;
}

apr_status_t rv;

for (i = 0; i < MAX_GROUP; i++)
{
if (0 == is_validate_group(i))
{
// Write it!
rv = apr_memcache_add(mc_groups[i], key, value, value_l, (apr_uint32_t) ttl, 0);
if (APR_SUCCESS == rv)
{
set_ct++;
}
}
}

RETURN_DOUBLE(set_ct);
}

在mc_get中,首先要随机选择一个组,然后从这个组开始轮询:

CODE:
/**
* Fetch a item from a random group
*/
PHP_FUNCTION(mc_get)
{
char *key, *value = NULL;
int key_l;
apr_size_t value_l;if (1 != ZEND_NUM_ARGS())
{
WRONG_PARAM_COUNT;
}

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, “s”, &key, &key_l) == FAILURE)
{
RETURN_MULL();
}

// I will try …
// Random read
apr_int32_t curr_group_id = random_group();
apr_int32_t i = 0;
apr_int32_t try = 0;
apr_uint32_t flag;
apr_memcache_t *oper;
apr_status_t rv;

for (i = 0; i < MAX_GROUP; i++)
{
try = i + curr_group_id;
try = try % MAX_GROUP;
if (0 == is_validate_group(try))
{
// Get a value
oper = mc_groups[try];
rv = apr_memcache_getp(mc_groups[try], p, (const char *) key, &value, &value_l, 0);
if (APR_SUCCESS == rv)
{
RETURN_STRING(value, 1);
}
}
}

RETURN_FALSE;
}

CODE:
/**
* Random group id
* For mc_get()
*/
apr_int32_t random_group()
{
struct timeval tv;
struct timezone tz;
int usec;gettimeofday(&tv, &tz);

usec = tv.tv_usec;

int curr = usec % count_group();

return (apr_int32_t) curr;
}

BSM_Memcache的使用方式和其它的client类似:

CODE:
<?php
$g1 = mc_add_group();    // 添 加第一个组
$g2 = mc_add_group();    // 添 加第二个组
mc_add_server($g1, ‘localhost:11211′);    // 在 第一个组中添加第一台服务器
mc_add_server($g1, ‘localhost:11212′);    // 在 第一个组中添加第二台服务器
mc_add_server($g2, ‘10.0.0.16:11211′);    // 在 第二个组中添加第一台服务器
mc_add_server($g2, ‘10.0.0.17:11211′);    // 在 第二个组中添加第二台服务器

mc_set(‘key’, ‘Hello’);    // 写 入数据
$key = mc_get(‘key’);    // 读 出数据
mc_del(‘key’);    // 删 除数据
mc_shutdown();    // 关闭所有组
?>

APR_Memcache的相关资料可以在这里找到,BSM_Memcache可以在本站下载。

◎APR环境介绍

APR的全称:Apache Portable Runtime。它是Apache软件基金会创建并维持的一套跨平台的C语言库。它从Apache httpd1.x中抽取出来并独立于httpd之外,Apache httpd2.x就是建立在APR上。APR提供了很多方便的API接口可供使用,包括如内存池、字符串操作、网络、数组、hash表等实用的功能。开发 Apache2 Module要接触很多APR函数,当然APR可以独立安装独立使用,可以用来写自己的应用程序,不一定是Apache httpd的相关开发。

◎后记

这是我在农历丙戌年(我的本命年)的最后一篇文章,由于Memcached的内涵很多,仓促整理一定有很多遗漏和错误。感谢新浪网提供的研究机会, 感谢部门同事的帮助。

NP博士 02-13-2007

原文发表于:http://www.54np.com/
转载请注明

XBMC TMDB Scraper 清除中文干扰-干净的削刮器

星期日, 八月 15th, 2010

TMDB - The Movie DB 在对付中国式电影名是力不从心,比如[中文译名].English Name.mkv。

原动力论坛的诸多帖子对9.11版根本无效。究其原因,advancedsettings.xml中的clearstrings字段不知为何失效。无论怎么配置都无法起到基本作用。

于是直奔主题,探索 C:\Program Files\XBMC\system\scrapers\video\tmdb.xml。

在打开Debug探查之后发现,当原始文件名为

[信使].The.Messenger.LIMITED.720p.Bluray.x264-CBGB.mkv

经过净化clearstings之后变成

[信使] The Messenger.mkv

前面的[信使]被当作电影名发给了TMDB,在tmdb.xml中得到的是编码之后的

%5b%e4%bf%a1%e4%bd%bf%5d%20the%20messenger

接下来就简单了,去除中文干扰,红色的是修改添加的部分,灰色的是去除的原始内容。

<CreateSearchUrl dest="3">
<RegExp input="$$1" output="&lt;url&gt;http://api.themoviedb.org/2.1/Movie.search/en/xml/57983e31fb435df4df77afb854740ea9/\2&lt;/url&gt;" dest="3">
<RegExp input="$$2" output="%20(\1)" dest="4">
<expression clear="yes">(.+)</expression>
</RegExp>
<expression clear="no" noclean="1">(^%5b.*%5d)*(.+)</expression>
<!-- expression noclean="1"/ -->
</RegExp>
</CreateSearchUrl>

这个方法仅对进口电影有效,如果您手里都是土鳖电影,还是直接连中文电影库吧。


Nihao,FreeBSD

星期五, 五月 21st, 2010

新公司,新的起点。

但是有一样东西没有变,那就是稳定毫无杂物,可以轻松自定义内核的Freebsd。

之前曾经用ISO光盘在HP 1U服务器上死活装不上网卡,最终只得装了Redhat,见 byebye了,freebsd

Linux这东东大多是二进制包商业行为更新,那种由被厂家挟持的所谓更新,就像Redhat的帽子突然收费一样,远远没有BSD Src Port来的稳定方便。

今天从京东进了台DELL 380,打算继续上2块硬盘RAID1做内网用不停机的测试服务器。

结果网卡又找不到了。

尝试着装回了DELL原配的Utunba Desktop,网卡倒是找回来了,看了下内存中跑的进程,什么乱七八糟的东西都有。

拆开机器,找到网卡芯片,字太小看不清楚,用手机拍了张照片,终于看清楚了。

XT701拍照还不错,这个芯片原大小只有不到5毫米。

顺着芯片组,找到了一个FreeBSD的一个2009年的Reversion,这个芯片在09年就支持了,而刻盘freebsd 8 iso发布的版本则要老得多。

解决的办法有2个。

安装系统时一定装上src,然后手工去源码树抓来,编译。

另一个方法更简单,兜里随时揣一块老PCI网卡,随时准备拧上去应急更新代码树。

Android Phone 超强……

星期二, 五月 11th, 2010

本想买HTC的G6/G7,但是在看到MOTO老大哥的产品备受米国推崇,外加上发现同去开会的Google的老兄也在用Moto Dorid,正好国内行货上市,带着地图,带着Wifi。

Moto的确很强悍,拿出了山寨机的功夫,在各项配置特别是外观上面都领先一步。以至于相比之下iPhone更像是一个没有Google支持的Droid。

本来是个联通的牺牲品,因为Google退出中国的时候,所有相关应用被联通封杀了。

但是因为有了这个Google服务包的存在,神机XT 701又恢复了魔力:

http://xt701.net/2010/03/17/xt701_update_gms_package_for_android201

为什么移动的用户要买联通的机器呢,那是因为TD-SCDMA+OPhone平台的组合实在太民工了,且不说低幼的CMCC公务员,就算是在法治社会,世界上也没有那个运营上能好一个自定义平台。

这不,等着携号转网开通之后就跑联通去……

用手机,不交费,拿Gtalk的VoIP打电话

星期四, 五月 6th, 2010

Symbian是落伍的OS,Andorid已经在高端毫无悬念击败了Nokia。

但是Nokia走低端路线走街机路线还是能挺好一阵子的。

如何在老Symbian/WM/Android手机上装MSN Gtalk ICQ Yahoo等等一干东东而且还能免费打越洋电话呢?

毕竟一个个地安装太费事了~

答案在这里:

http://www.talkonaut.com/

这个免费的东西,可以支持三大手机平台,可以同时登陆各主流IM,可以支持花GPRS的钱语音通话,可谓强大。

最搞的是当有人给你打Gtalk电话的时候,操作跟真的电话一样……

抵制吸血驴 抵制迅雷 抵制KFC

星期三, 四月 7th, 2010

ADSL,上下传均开满无限制,7x24挂着。所有下载、存档文件夹均共享。原来用官方版.49c,无反吸血,几个月用下来,上/下传比高达4:1,上传永远是满的,下载经常不满。

自从用了反吸血Xtreem MOD版之后,上/下传比保持在1:2.61。已经变成上传1K下传2.6K。上下载都是满的。

推测其中原因,应该是迅雷用户完成自己的下载完成之后,迅雷自动杀掉还在排队的人,自己跑了。不得不承认,这种流氓作风很符合诸多天朝愤青心态,但是这种短视的行为,带来的是对整个体系的伤害。

看统计杀掉的迅雷数量已经有4000+,剩下的用户60%+是VeryCD客户端。

偶们的带宽使用全世界最贵的价钱买的,偶们包月1M ADSL的费用在香港可以买到30M光纤。而且偶7x24开机,每天耗电4度,XL的流氓众不但在吸大家的宽带费,还有电费。

现在好了,封掉XL之后,世界变成了两个团体,流氓团体和非流氓团体。流氓团体的运作逻辑和BT一样,而emule还是emule。

其实从逻辑上来说,如果要跟流氓打交道,得比流氓还流氓才行……所以在XL的流氓世界里,你需要一个外挂,做的是下载之后连30分钟都不要等,立刻杀掉上传队列~~这才叫迅雷~~

所以说,流氓的世界永远是负循环。

最后补充,有识之士建议大家不用Verycd的驴,该公司的产品因利益关系已经与迅雷合作,同流合污一丘之貉。

另外,有小道消息说Verycd公司疑似违反了GNU协议,偷窃amule代码并封闭资源。

Xtreme现在由继任者继续开发。

download 直接下载地址

bin 可执行包:
emule0.49c-Xtreme7.2.7z

source 源代码:
emule0.49c-Xtreme7.2-sources.7z


Outlook到Google Calendar到Symbian Phone全攻略

星期四, 三月 4th, 2010

为什么要同步到手机,因为手机是个闹钟+记事本,会在会议前提醒你,并且奉送上Agenda。

如果有管理员权限,而且不介意把自己的手机搞成Outlook克隆的话,装一个Nokia Suite可以通过蓝牙搞定Outlook <-> Nokia的双向同步。但是后果就是私人电话本和日程会将与Outlook的企业内容混合,一个乱字了得。

但我所遇到的问题是,Outlook都是公司的Exchange Server,躲在万千防火墙之后,除公司黑莓/iPhone之外,闲杂人等不得访问。而Google Calendar是私人的,里面充满了F1赛事信息等非工作内容。

(全文 ...)

正确设置wifi规避干扰

星期二, 十月 27th, 2009

800px-Long_Distance_802.11_Wi-Fi_-_dish,_Venezuela

超远距离WiFi传输……

很多WiFi信号貌似很强,但是很不禁用,大文件传输经常断线,这就是所谓的虚假繁荣。

绝大多数WiFi网卡的信号强度格数都是虚假的,即便是“国际名牌”想在中国这地头上混也得弄虚作假。

把这些虚假信号打回原形的手段也很简单,用这条命令:

ping -n 100 -l 1024  x.x.x.x

把x.x.x.x换成你的路由器地址,顺便把Windows防火墙临时关掉。如果得不到100%成功率,那么这个无线网一定有问题。要么是距离太远,要么是干扰太严重。

干扰

很多东西可以干扰WiFi,比如千万不要买2.4G无绳电话,买有绳的,或者更原始的27M的,要不就是更先进的5G的,总之避开当今热点2.4G。

尽量避免使用2.4G无线鼠标键盘,不是一定干扰,但是有很大干扰的可能性。

不过最可恨的就是——另一个同频道WiFi基站,这个东西的功率、调制方式和你是一模一样,两个AP在一起互相干扰,给人的感觉就是——信号满满、速度超慢、很不稳定。

设置

当出现AP干扰之后,就需要设置技巧了。

如何正确设置,需要先学习下802.11的频谱和信道组成。

其实……802.11只有3个能用的信道,其他都是偏移但重叠的。

你需要先搞清楚你家附近有多少讨厌的邻居,可以用这个Netstumbler

然后对照下图

80211-frequency-channel-map

你需要先搞清楚你家附近有多少讨厌的邻居,可以用这个Netstumbler

然后对照上面的图,尽量回避开。

802.11N遇到的问题就比较麻烦了,我需要占用2个信道40Mhz才能展开300M的带宽,但是讨厌的邻居有个强的信号在6频道,上下都躲不开。

在不改变发射机任何性能的情况下,通过优化天线获得增益也是对付干扰的好办法,将无方向天线修改为定向天线。有时候一些DIY,和另一些DIY还是有点用的。这里有专业指导 http://www.freeantennas.com/


XP Pro共享文件夹无法访问

星期六, 十月 24th, 2009

简单的说就是权限混乱,而且XP Pro没有提供Server版的权限菜单可以通过GUI恢复。

但是可以通过建立BAT文件,命令行方式解决问题。如果是通过标准的Guest用户访问,用下面这句就可以了:

cacls.exe "." /T /E /G Guest:F

完整的BAT如下,是需要而定可以打开不同的设置。

rem cacls.exe "." /T /G BUILTIN\Administrators:F
rem cacls.exe "." /T /E /G System:F
rem cacls.exe "." /T /E /G BUILTIN\Users:R
rem cacls.exe "." /T /E /G Everyone:R
cacls.exe "." /T /E /G Guest:F
rem cacls.exe "." /T /E /G "BUILTIN\Power Users":C

原文:http://windowsxp.mvps.org/sdperms.htm