listen函数中的backlog字段

今天在公司无意间又拿redis-benchmark测了一下silly的IO并发性并与redis本身比较了一下。

发现在2000个client同时并发的情况下,性能只是Redis的30%的左右。

直觉上这很不正常,虽然silly所有的数据经过lua层时都需要malloc和memcpy,但最多性能上差个10%~20%就已经很可观了,绝对不可能差70%这么多。

通过不断的调整client的个数,我发现性能并没有明显随着client的数量降低而降低,而是在client个数到达某个值时突然降低的。

比如我自己测的数据是在491个client时,silly的性能与redis相差无几,但在492个client同时并发时,silly的性能锐降到redis 30%左右。

这也再次说明了应该不是malloc和memcpy造成的开销。

在此期间,我分别尝试加大epoll的缓冲区和增大socket预读缓冲区,都没有明显的效果。这也说明问题并不在IO的读取速度上和系统调用开销上。

万般无奈之下Download下来redis3.0的源码开始对着比,最终发现惟一不一样的地方就是redis的listen的backlog竟然是511,而我的只有5.

一下子豁然开朗了,由于backlog队列过小,导致所有的connect必须要串行执行,大部的时间都在等待建立连接上,在将backlog的值改为511后,性能已然直逼redis。

google了一下发现,除了redis连nginx竟然也是用511。但是记忆中backlog参数会影响未完成连请求队列的大小,似乎增加backlog会增加syn洪水攻击的风险。

查了好一会资料,最后发现man上早都指出在Linux 2.2之后listen中的backlog参数仅用于指定等待被accept的已完的socket队列的长度。未完成连接的队列长度则通过/proc/sys/net/ipv4/tcp_max_syn_backlog来指定。

至于为什么backlog是511而不是512, 是因为kernel中会对backlog做roundup_power_of_tow(backlog+1)处理,这里使用511实际上就是为了不浪费太多不必要的空间。

之前一直看资料上说backlog是个经验值,需要根据经验调节。然而并没有想到,当大批量连接涌入时,backlog参数会起到这个大的影响。那么这个经验看来就是要估算每秒的连接建立个数了。

比如web服务器由于http的特性,需要频繁建立断开链接,因此同一时刻必然会涌入大量连接,因此可能需要更高一些的backlog值,但是对于游戏服务器来讲,大多都是长连接,除了刚开服时会有大量连接涌入,大部分情况下连接的建立并不如web服务器那么频繁。当然即使如此依然需要对每秒有多少链接同时进入进行估算,来衡量backlog的大小。

虽然可以不用估算直接使用backlog的最大值,但却可能会造成‘已完成未被Accept的socket的队列’过长,当accept出队列后面的连接时,其已经被远端关闭了。

经过测试,即使backlog为63,在局域网内同时并发2000客户端并无性能影响。


12月23日纠下补充:
1. listen的backlog值其实是会精确指定accept的队列的,只不过它除了控制accept队列的大小,实际上还会影响未完成的connect的队列的大小,因此
roundup_power_of_tow(backlog+1)增大的实际是未完成connect队列的大小。
2. /proc/sys/net/ipv4/tcp_max_syn_backlog 虽然字段名中有一个sync但其实限制的是accept队列的大小,而并非是未完成connect队列的大小

虽不欲写成kernel net源码解析的文件(实际上是怕误人子弟:D), 但还是走一下流程证明一下吧(只针对tcp和ipv4基于3.19)。

先看listen的整个流程:

listen系统调用 其实是通过sock->ops->listen(sock, backlog)来完成的。

那么sock->ops->listen函数是咋来的呢,再来看socket系统调用, 其实是通过socket_create间接调用__sock_create来完成的。

sock->ops->listen函数则是通过__socket_create函数中调用pf->create来完成的。而pf其实是通过inet_init函数调用socket_register注册进去的,至于什么时间调用了inet_init这里就不赘述了,毕竟这不是一篇kernel分析的文章:D.

由此我们找到pf->create实际上调用的就是inet_create函数.

啊哈!接着我们终于通过inetsw_array找到sock->ops->listen函数最终其实就是inet_listen函数。可以看到我们通过listen传入的backlog在经过限大最大值之后,直接被赋给了sk_max_ack_backlog字段。

OK,再来看一下kernel收到一个sync包之后是怎么做的

好吧,先去看icsk->icsk_af_ops->conn_request这个函数是怎么来的。

回过头来看inetsw_array发现其中SOCK_STREAM中类型的prot字段其实是指向tcp_prot结构体的。

前面看过的的inet_create函数中的最后部分会调用sk->sk_prot->init函数。而sk_prot字段其实是通过调用sk_alloc时将inetsw_array中的prof字段赋值过去的。

因此在inet_create函数的最后sk->sk_prot->init调用的实际上是tcp_v4_init_sock函数。而在tcp_v4_init_sock函数中会将icsk->icsk_af_ops的值赋值ipv4_specific的地址。由此终于找到了icsk->icsk_af_ops->conn_request其实就是tcp_v4_conn_request函数,此函数随即调用tcp_conn_request函数来完成之后的内容。

在tcp_conn_request中是通过sk_acceptq_is_full来判断的。
从sk_acceptq_is_full函数中看到他是通过sk_max_ack_backlog字段判断的,而这个字段在我们分析listen系统调用时已然看到其实就是listen传入的那个值。

另外需要额外说明的时,在reqsk_queue_alloc中为的listen_sock::syn_table分配的空间仅仅是一个hash表,并不是际的request_sock空间。

SIGPIPE信号

昨天夜里实现了按行来切为数据包的协议, 今天就迫不及待使用resdis-benchmark来测试一下silly的性能。

结果发现到100000个请求左右时就有一定机率程序会默默的退出, 使用gdb看了一下, 是因为向socket写入数据时触发了SIGPIPE信号。

google了一下发现,当向一个已经关闭的socket第二次写入数据时,就会触发SIGPIPE。

但是我把所有的_socket_close都加了打印也没有发现问题。

最后偶然间发现,如果一个socket被对方关闭, 那么第一次write函数不一定返回出错, 但是第二次write却一定会触发SIGPIPE, 而SIGPIPE的默认行为则是退出运行。

假设Client和Server按如下顺序运行则会出现上述情况:
Client connect
Server accept
Client send
Server recv and process data
Client close
Server write result(此时write有一定机率依然会返回写入数据的长度,并不报错)
Server write result2(此时即会触发SIGPIPE信号, 导致程序退出)

因此在写socket程序, 如无特殊需要一定要使用signal(SIGPIPE, SIG_IGN)来忽略SIGPIPE信号, 不然这会是一个大坑。

linux下调试内存问题

因为linux下没有QQ,刚好我的mac mini在闲置, 于是尝试着在OSX下开发silly

令人奇怪的是在我的linux机器下运行好好的程序, 在osx下只要client对着silly发送几个数据包就会导致silly直接崩溃, 调试半夜未果。

今天早上在地铁上我都甚至开始怀疑osx下的malloc库默认不是线程安全的, 但是地铁上查了一路依然不能确定。

到了公司后, info程序员还没到,我就又寻思着我那个bug, 在centos下又测了一次,依然无果。

不死心看了一下’男人’对malloc怎么说, 无意间看到linux下有一个环境变量叫MALLOC_CHECK_, 可以为下面的值:

0 – 不产生错误信息,也不中止这个程序
1 – 产生错误信息,但是不中止这个程序
2 – 不产生错误信息,但是中止这个程序
3 – 产生错误信息,并中止这个程序

在终端下执行了export MALLOC_CHECK_=1, 然后再次启动silly, 当客户端连接时silly直接报错, 终于找到根源所在。

犯了个低级错误,在向worker发消息会首先使用malloc分配silly_message结构体所占用的空间, 然后再分配silly_socket_message所占用的空间, 在分配silly_socket_message所占的内存空间时我本意是要使用sizeof(*socket)来计算需要使用的内存大小(socket为一个struct silly_socket_message结构体的指针),却因为手误打成了sizeof(socket)。这实际上才分配了8个字节(64位机器),所有针对这地内存的操作实际上都是溢出行为。

由于64位机器上的指针长度要比32位机器上的指针大一倍, struct silly_socket_message仅仅才16个字节,那么在64位机器上溢出的程度要小于32位机器,这也解释了当初没有在意的silly在清风同学的32位VPS机器上很大概率崩溃的现象,其实是因为溢出太多导致。

linux下动态库的版本号

据说linux下的动态库管理机制可以避免微软件DLL Hell的问题.

今天抽了点时间研究了一下, 发现其实本质上是利用别名(soname)技术来实现的.

在编译so文件时, 通过参数-soname将别名传入链接器ld(gcc可通过参数-Wl来将-soname参数传入链接器), 那么生成的动态库文件中Dynamic section中的SONAME将会被填入输入的别名. 如果没有-soname参数, 则Dynamic section中将不会有SONAME字段生成.

当使用命令gcc -g -Wall -o main -L. -lver时, 在进行链接时, 链接器ld会首先去当前目录查找libver.so, libver.so也被称为链接名字, 链接器会提取libver.so中的SONAME字段中的名字作为运行时要加载的动态库的名字, 如果没有SONAME字段则使用链接名字作为运行时要加载的动态库的名字(可通过readelf -d file来查看).

linux下为了更方便我们管理动态库, 提供了ldconfig程序. ldconfig的主要功能就是搜索/lib, /usr/lib, /etc/ld.so.conf内所列的目录, 提取动态库的SONAME,并将其作为软链接的名字来建立软链接, 以使程序运行时可以按别名加载.


一个具体例子来说明上述机制是怎么避免DLL Hell问题.

可执行文件main中依赖于一个动态库liba.so.
编译liba.so时可以使用gcc -g -Wall –shared -fPIC -o liba.so sourcefiles -Wl,-soname,liba.so.1来生成liba.so
编译main时可以使用gcc -g -Wall -o main -L. -la, 链接时依来liba.so动态库, 运行时依赖的实际上是liba.so.1文件(liba.so文件的别名)

当main程序发布时, 附带的动态库文件名为liba.so.1.1.3(SONAME为liba.so.1), 安装程序时将liba.so.1.1.3拷贝到/usr/lib/目录下, 然后运行ldconfig, 将会自动生成liba.so.1的软连接指向liba.so.1.1.3.
如果以后liba.so有bug修改且没有接口修改(兼容之前发布的main程序), 那么单独发布liba.so.1.2.1 (SONAME为liba.so.1) 文件并将其拷内到/usr/lib/目录下运行ldconfig, ldconfig会自动更新软连接liba.so.1指向liba.so.1.2.1.

如果是使用dlopen动态加载则直接使用dlopen(“liba.so.1”, xxx)来指定所需要的动态库的主版本号即可.

这样就避免了多个版本的动态库相互覆盖的问题, 也就从根本上避免了DLL Hell的问题.

linux下动态库

今天无意间发现在linux下share object(dynamic library)中的函数竟然可以不通过回调的方式直接访问主程序中的函数,瞬间颠覆以前对于动态库的观念.

代码所示libhi.so中有一个函数hello, 主程序main中有一个函数hi_out, 那么在main中调用libhi.so中的hello时,hello会自动找到main程序中的hi_output函数地址, 然后进行调用.

在感叹linux下动态库强大的同时, 对于其实现机制也产生了好奇. 经过一番努力终于在程序员的自我修养中第7.6.2章找到答案.
“动态链接器在完成基本自举后, 动态链接器将可执行文件和链接器本身的符号表都合并到一个符号表中, 我们可以称它为全局符号表(Global Symbol Table)…..当一个新的share object被装载进来的时侯, 它的符号表会被合并到全局符号表中”, 因此其实libhi.so在调用hello函数时实际上是从全局符号表中找到hi_out函数的地址并进行调用, 本质上libhi.so并不知道这个hi_out是属于另一个share object还是属于main程序中.

但当我使用dlopen系列函数动态加载libhi.so时, 却总是加载失败提示找不到hi_out函数. 理论上静态加载与动态加载上的行为应该是一样的, 只不过静态加载时dlopen将会被隐式调用而已.

ld的手册找到了答案, ld在生成可执行文件时, 默认只导出被其他动态库使用的符号. 因为是使用dlopen去动态加载libhi.so, 那么链接时ld并不知道可执行文件中的hi_out会被外部引用, 也就不会导出hi_out到动态符号表去. 当dlopen打开libhi.so时, 动态链接器在全局符号表中找不到hi_out符号, 理所当然就报错了.

要解决这个问题只要给链接器加上参数-E将主程序中所有全局符号放到动态符号表中即可, 由于生成可执行文件一般都是gcc直接生成, 因此可以使用gcc -Wl,-E来将-E参数传给ld来完成创建一个可以被动态链接的可执行文件.

实现了一个coroutine

在学习了lua之后, 总算是搞清楚了颇为流传的coroutine是怎么回事. 我发现coroutine就是我一直希望使用的那种多任务处理方式, 即有线程的清晰抽象, 又可以避免锁带来的开销以及其他并发问题, 可以说是线程和异步处理的一个最佳折中点.

在大约一年前, 我一直在为不能控制多线程的调度而苦恼(那里还不知道在Windows下Sleep(0)可以暂时让出cpu的控制权), 我甚至试图使用状态机来模拟多线程以便我可以控制线程调度, 后来因为这个方法对于代码的可维护性来讲付出的代价太大, 最终没敢使用. 再后来又饱受线程同步, 锁碰撞造成上下文切换的困扰. 在coroutine概念中, 每一个coroutine自已来决定什么时间来让出cpu时间, 由于是coroutine自行让出cpu执行时间, 那么也就不存在有些操作被中断的问题, 自然也就避免了锁碰撞的问题.

lua的coroutine是半对称的, 因此最坏的情况要比对称的coroutine多出一倍的开销. 但是相比对称协程而言半对称协程的调度可以更灵活, 逻辑上也更为清晰, 而对称协程则使得程序略显不清晰, 每一个协程可能需要对整个协作过程有所了解, 当然是否要使用对称coroutine就要看情况而定. 花了大概一天半业余时间终于实现linux和Windows版本的coroutine, 以后会尽量采用coroutine而非thread来解决多任务工作.

btw, 协程与线程相比, 开销就小在不会有锁碰撞造成上下文切换, 但是coroutine的切换不当有时候可能会比线程的锁碰撞带来的开销更大, 因此在写coroutine时一定要注意.


2月1号补充:
原生协程是在用户态切换上下文因此要比类似swapcontext之类的系统调用销小很多.
2月4号补充:
线程开销除了context切换开销之外还有调度开销.

POSIX线程中的条件变量与互斥量

在看到UNP第26章时发现对于linux下的线程模型还很不是非常了解. 翻到APUE的第11章, 发现POSIX线程中通用的两个线程交互与同步手段有互斥量和条件变量两种.

对于这两种同步手段我想了很久也没想到每种到底适用于哪些场景, 甚至于我觉得几乎mutex就够完成绝大部分线程同步功能了. 以前在写代码时都是自然而然的用出来了, 也从来没有认真总结过到底什么情况下使用Mutex, 什么下使用条件变量(类似Windows下的事件).

google到这篇文章终于豁然开朗. 其实问题很简单, 也许换个描述方式就更容易说明问题, Mutex是用来在线程内来保证操作的原子性, 可以称为同步手段. 而条件变量是用来线程间通信使用的. 如Mutex在某一线程Get之后, 从此这个Mutex就属于这个线程, 只有Get到这个Mutex的线程才能将其释放. 而条件变量则不然, 线程A设置过条件变量后, 线程B即可访问, 反之线程B设置条件变量之后线程A也可以访问. 因此多线程编码中当需要保证于某一操作的原子性时则使用Mutex, 当线程间需要相互通信时则需要使用条件变量.


在下班回来的路上, 大概回忆了一下代码中多线程的地方, 发现其实并非没有用到条件变量(Windows下的事件)的地方, 只是因为我都是顺手就写成while (flag == flase) sleep(x)这种查询的方式, 如果将查询换成条件变量之后, 此线程被唤醒的次数将大大降低对CPU时间的浪费将会更少.


1月14日补充:
条件变量只有在pthread_cond_wait进入sleep之后, pthread_cond_signal函数执行才能将pthread_cond_wait函数唤醒, 如果一个线程先执行pthread_cond_signal函数, 随后另一个线程执行到pthread_cond_wait时依然会被挂起. 这点与Windows下的Event并不相同, Windows下的Event不论是先于WaitForSingleObject去设置Event还是后于WaitForSingleObject, 只要Event被设置WaitForSingleObject都能正常返回.

~/.fvwm/fvwm.stroke

#strokes
#window list without drag
Stroke 0 0 R N WindowList

#button 3 guesture with Ctrl starts programs in any context
#"r" like guestures starts rxvt
#Stroke N5456 0 A C Exec exec xkill
#Stroke N65456 0 A C Exec exec xkill
#Stroke N7414789 0 A C Exec exec rxvt
#Stroke N7414759 0 A C Exec exec rxvt
#Stroke N74147589 0 A C Exec exec rxvt
#Stroke N7414756 0 A C Exec exec rxvt
#Stroke N74156 	0 A C Exec exec rxvt
#Stroke N74159 	0 A C Exec exec rxvt
#Stroke N7536951 0 A C Exec exec xterm
#Stroke N9514753 0 A C Exec exec xterm
#Stroke N7412369 0 A C Exec exec gvim
#Stroke N1478963 0 A C Exec exec mozilla
#Stroke N7896321 0 A C Exec exec stardict
#Stroke N9874123 0 A C Exec exec drscheme
#先用这么多吧
Stroke N258 0 R C Exec exec  rxvt -geometry 80x50+105+160 
               -sr -tr -sh 90 -bg black -fg wheat 
               -fn "-adobe-courier-medium-r-*-*-14-*-*-*-*-*-*-*"
Stroke N852 0 R C Exec exec gnome-terminal 
#打开网页浏览器
Stroke N9874123 0 R C Exec exec iceweasel
Stroke N87413 0 R C Exec exec iceweasel
Stroke N987412 0 R C Exec exec iceweasel
Stroke N87412 0 R C Exec exec iceweasel
#打开虚拟机
Stroke N753 0 R C Exec exec virtualbox
#用于关闭窗口
Stroke N5456 0 R C Exec exec xkill
Stroke N65456 0 R C Exec exec xkill
#用于开启spb
Stroke N456 0 R C Exec exec projmgr 

#
#grow horizontal and vertically
#Stroke N258 0 TSF2 N Maximize True 0 growup
#Stroke N852 0 TSF2 N Maximize True 0 growdown
#Stroke N456 0 TSF2 N Maximize True growright 0
#Stroke N654 0 TSF2 N Maximize True growleft 0

#grow bidirectional
#Stroke N25852 	0 TSF2 N Maximize True 0 grow
#Stroke N5852 	0 TSF2 N Maximize True 0 grow 
#Stroke N85258 	0 TSF2 N Maximize True 0 grow 
#Stroke N5258 	0 TSF2 N Maximize True 0 grow 
#Stroke N65456 	0 TSF2 N Maximize True grow 0
#Stroke N5456 	0 TSF2 N Maximize True grow 0
#Stroke N45654 	0 TSF2 N Maximize True grow 0
#Stroke N5654 	0 TSF2 N Maximize True grow 0

#grow diagonally
#Stroke N159 	0 TSF2 N Maximize True growright growup
#Stroke N951 	0 TSF2 N Maximize True growleft growdown
#Stroke N753 	0 TSF2 N Maximize True growright growdown
#Stroke N357 	0 TSF2 N Maximize True growleft growup
#Stroke N5159 	0 TSF2 N Maximize True grow grow
#Stroke N5951 	0 TSF2 N Maximize True grow grow
#Stroke N5753 	0 TSF2 N Maximize True grow grow
#Stroke N5357 	0 TSF2 N Maximize True grow grow

#reverse to unmaximized
#Stroke N74123 0 TSF2 N Maximize False

#window functions
#Stroke 0 	0 TSF	N RaiseLower
#Stroke 0 	0 2   	N Maximize-Func
#Stroke 0 	0 A	C Lower
#Stroke N852 	0 A C Iconify

#Drag mouse on the root window
#Mouse 1 R C StrokeFunc DrawMotion 
#Mouse 1 R A StrokeFunc DrawMotion 

#Drag mouse with Ctrl key
Mouse 3 R A StrokeFunc DrawMotion

#Drag mouse on the border
#Mouse 3 TSF N StrokeFunc DrawMotion

#Drag mouse 1 on the maxmize button
#Mouse 1 2 N StrokeFunc DrawMotion 

~/.fvwm/.fvwm2rc

ImagePath +:/usr/share/icons:/usr/share/pixmaps:/usr/share/icons/hicolor/48x48/apps:/usr/local/share/fvwm/icons:$HOME/.fvwm/icons
EdgeResistance 250 100
EdgeScroll 100 100
EdgeThickness 10
ColormapFocus FollowsMouse
ClickTime 750
DeskTopSize 2x2
#忽略数字锁定键
IgnoreModifiers L25

# default Styles:
Style * BorderWidth 5, HandleWidth 5, DepressableBorder
Style * Icon kcmkwm.png
Style * MWMFunctions, MWMDecor, MWMButtons, HintOverride
Style * DecorateTransient, NoPPosition
Style * SloppyFocus, MouseFocusClickRaises
Style * SmartPlacement
Style * Font  -*-simsun-medium-r-*-*-14-*-*-*-*-*-*-*
Style * IconFont  -*-simsun-medium-r-*-*-12-*-*-*-*-*-*-*
Style * HilightFore black, HilightBack gainsboro
Style * IconBox 360x200+1-1, IconFill left bottom

Style * WindowShadeShrinks, WindowShadeSteps 100

TitleStyle height 22
AddTitleStyle ActiveDown VGradient 8 gold black

MenuStyle * MWM
MenuStyle * PopupDelayed, PopupDelay 160, Animation, TitleWarp
MenuStyle * Foreground gold, Background gray40
MenuStyle * ActiveFore White
MenuStyle * Font  -*-simsun-medium-r-*-*-14-*-*-*-*-*-*-*
MenuStyle * MenuFace VGradient 64 darkgray MidnightBlue
#MenuStyle * MenuFace TiledPixmap weird10dark.xpm

ButtonStyle All -- UseTitleStyle
ButtonStyle All ActiveDown VGradient 8 palevioletred black

ButtonStyle 1 Vector 7 
  65x15@0 25x55@1 45x55@0 35x85@1 75x45@0 55x45@1 65x15@0
ButtonStyle 6 16 20x20@1 30x20@1 50x40@1 70x20@1 80x20@1 80x30@0 60x50@0 80x80@0 70x80@0 50x60@0 30x80@0 20x80@0 20x70@0 40x50@1 20x30@0 20x20@1

CursorStyle ROOT 58
CursorStyle TITLE 62
CursorStyle STROKE 86


# Styles for various Fvwm modules:
Style "Fvwm*"       Layer 5,  NoTitle,  Sticky, WindowListSkip
Style "Fvwm*"       BorderWidth 2, CirculateSkipIcon, CirculateSkip
Style "FvwmPager"   StaysOnTop
Style "FvwmBanner"  StaysOnTop
Style "FvwmButtons" Icon toolbox.xpm, NeverFocus
Style "FvwmConsole" SloppyFocus

# Styles for your common terminal emulator programs:
Style "xterm"       Icon /usr/share/icons/Bluecurve/48x48/apps/gnome-term-tiger.png, SloppyFocus
Style "rxvt"        NoTitle, Icon /usr/share/icons/Bluecurve/48x48/apps/gnome-term-linux.png
Style "gv"	    ClickToFocus
Style "mozilla"	    RandomPlacement, SloppyFocus
#Style "Allegro*"    Layer 5 
Style "NoResource" NoTitle BorderWidth 0, HandleWidth 0
Style "xdaliclock" NoTitle, NoHandles, Sticky, WindowListSkip, ClickToFocus, Layer 6
Style "MPlayer" NoTitle, Layer 7
Style "RealPlayer" Layer 7
Style "XSIM"	    Layer 7, NoTitle, HandleWidth 1, Sticky, WindowListSkip
Style "emacs"	    Icon gnu-animal.xpm
Style "gv"	    Icon gv.xpm
Style "Xdvi help"	NoTitle
Style "AcroRead"	VariablePosition, VariableUSPosition
Style * RaiseTransient LowerTransient StackTransientParent
#Style * NoActiveIconOverride
Style "Oracle VM VirtualBox*" MoveToPage 2

# Styles for various common programs:
Style "xbiff"       NoTitle, Sticky, WindowListSkip, ClickToFocus
Style "xcalc"       Icon xcalc.xpm, NoButton 2,RandomPlacement,ClickToFocus
Style "xmh"         Icon mail1.xpm, NoIconTitle,StickyIcon
Style "xmh"	    RandomPlacement, NoButton 2
Style "xman"	    Icon xman.xpm, RandomPlacement, ClickToFocus
Style "xmag"	    RandomPlacement, ClickToFocus
Style "FvwmButtons"	BorderWidth 0,NoHandles


#Read fvwm.strokes
# some simple default key bindings:
#Key Tab A M -
Key Next         A       SCM     Next [*] Focus
Key Prior        A       SCM     Prev [*] Focus

#在不同的桌面间移动
Key F1 A M  MoveToDesk 0 0 
Key F2 A M  MoveToDesk 0 1
Key F3 A M  MoveToDesk 0 2
Key F4 A M  MoveToDesk 0 3

#Key F1 A M GotoDesk -1
#Key F2 A M GotoDesk 1
#用于实现ctrl+alt+a截屏
#Key A  A CM Exec exec gnome-screenshot -a
Key A  A CM Exec exec ~/scripts/screenshot.sh

#用于实现Win+D
#Key D A 4 All(.*) Iconify True
Key D A 4 All (AcceptsFocus CurrentPage !Iconic !Shaded, !FvwmTaskBar, !FvwmButtons, !xdaliclock)Iconify 

#Mouse 1 A M MoveToDesk 1 0
#Mouse 3 A M MoveToDesk 0
#Mouse 1 A M MoveToDesk 1

Mouse 3 A M Iconify True
Mouse 1 A M Iconify False



Key F3 M A Module FvwmConsole -terminal rxvt -geometry 45x5-0+0 -bg gold -fg midnightblue -fn "-adobe-courier-medium-r-*-*-14-*-*-*-*-*-*-*"
Key F5 A C Exec exec import -window root shot.png
Key F11 A C Exec xscreensaver-command -lock

# some simple default mouse bindings:
Mouse 1	R   	A       Menu RootMenu Nop
Mouse 3	R   	A       Menu AssistantMenu Nop
Mouse 2	R    	A      	Menu ProgramsMenu Nop

Mouse 3 WI	SC	CloseOrNot
Mouse 3	A   	MC      Menu RootMenu Nop
Mouse 3 A	S	Move

DestroyFunc CloseOrNot
AddToFunc CloseOrNot
+ C Silent Close
+ M Nop

#   for the title bar buttons:
Mouse 1	4    	A     	Iconify
Mouse 1 6	A	Close
Mouse 3	2    	A     	Maximize-Func2

#   for other parts of the window/borders/icons:
Mouse 1	F	A	Resize-or-Raise
Mouse 1	TS	A	Move-or-Raise
Mouse 1	I	A	Move-or-Iconify

######################## Initialization Functions ############################
DestroyFunc StartFunction
AddToFunc StartFunction   	
+ I Module FvwmButtons MainPanel
#+ I Module FvwmAuto 500 Raise Nop
+ I Module FvwmAnimate
+ I Module FvwmTaskBar
+ I Module FvwmPager 0 3
+ I Exec exec xdaliclock -transparent -geometry +842+0 -fg green
+ I Exec exec xloadimage -onroot -fullscreen ~/.fvwm/icons/desktop1.jpg 

+ I Exec exec xsim
+ I Exec exec naultilus.sh
#启动gnome菜单
#+ I Exec exec gnome-panel
#启动mail提醒
#+ I Exec exec mail-notification --sm-disable
#启动网络配置
+ I Exec exec ~/scripts/network.sh
#启动fetchmail
+ I Exec exec ~/scripts/fetchmail.sh

DestroyFunc InitFunction
AddToFunc InitFunction 	  
+ I Exec exec xscreensaver -no-splash

DestroyFunc ExitFunction
AddToFunc ExitFunction
+ I All (xdaliclock) Close
+ I All (xscreensaver) Close
+ I All (xsim) Close
+ I All (naultilus) Close
#+ I All (gnome-panel) Close
#+ I All (mail-notification) Close
+ I All (~/scripts/network.sh) Close
+ I All (~/scripts/fetchmail.sh) Close

######################## Menus ###################

DestroyMenu RootMenu
AddToMenu RootMenu	"Root Menu"	Title
+			"&xterm%mini.display.xpm%"	Exec exec gnome-terminal
+			"&Rxvt%mini.monitor.xpm%"	Exec exec rxvt
+			"&Big Rxvt"	Exec exec rxvt -geometry  78x43
+			""		Nop
+                       "&Programs"      Popup ProgramsMenu
+			""	        Nop
+                       "&System"        Popup SystemMenu
+			""		Nop
+                       "&Utilities"     Popup UtilitiesMenu
+			""		Nop
+                       "&File"          Popup FileMenu
+			""		Nop

+                       "Re&fresh Screen"   Refresh
+                       "Re&capture Screen" Recapture
+			""		Nop
+                       "&Lock"         Exec exec xscreensaver-command -lock
+			"&Exit Fvwm%mini.exit.xpm%"	Popup Quit-Verify

DestroyMenu ProgramsMenu
AddToMenu "ProgramsMenu" "Programs" Title
+			"&VIM"  Exec exec gvim
+			"文件管理"  Exec exec nautilus --no-desktop
+			"mo&zilla" Exec exec iceweasel
+                       "星际译王" Exec exec stardict

DestroyMenu SystemMenu
AddToMenu "SystemMenu" "System" Title
+                       "xkill" Exec exec xkill
+                       "NetWork Restart" Exec exec ~/scripts/netrestart.sh

+                       "关机"  Exec exec ~/scripts/shutdown.sh
+                       "重启"  Exec exec ~/scripts/restart.sh

DestroyMenu UtilitiesMenu
AddToMenu UtilitiesMenu  "Utilities" Title
+			"Top"		Exec exec xterm -T Top -n Top -e top
+			"Calculator"	Exec exec xcalc
+			"Xman"		Exec exec xman
+			"Xmag"		Exec exec xmag
+			""		Nop
+                       "Reset X defaults" Exec xrdb -load $HOME/.Xresources 
+  			"screenshot" 	Exec import -window root shot.png

DestroyMenu FileMenu
AddToMenu "FileMenu" "File" Title
#+                       "&Home"         Popup HomeDirMenu
+                       "&Device"         Popup DeviceMenu

#DestoryMenu HomeDirMenu
#AddToMenu  "HomeDirMenu"
#        PipeRead 'for i in $HOME/*;
#                 do echo "+ $i Exec xterm -e vim $i";done'
//添加自动挂载的设备
DestoryMenu DeviceMenu
AddToMenu  "DeviceMenu"
+ DynamicPopupAction  Function MakeMedia
 
AddToFunc MakeMedia
+ I DestroyMenu recreate DeviceMenu
+ I AddTomenu DeviceMenu Devices Title
+ I PipeRead 'for i in /media/*;
                 do echo AddToMenu DeviceMenu "$i"  Exec exec ~/scripts/umount.sh  $i;done'
   
DestroyMenu Quit-Verify 	
AddToMenu Quit-Verify 	"Really Quit Fvwm?" Title	
+		      	"Yes, Really Quit"  Quit	
+                       "Restart Fvwm2"     Restart fvwm2
+		      	"No, Don't Quit"    Nop	



######################## Sample Functions ##########################
DestroyFunc Move-or-Raise		
AddToFunc Move-or-Raise		I Raise
+				"M" Move
+  				"D" WindowShade
DestroyFunc Move-or-Raise2	
AddToFunc Move-or-Raise2	"M" Raise
+				"M" Move
+  				"D" Lower
DestroyFunc Maximize-Func		
AddToFunc Maximize-Func		"M" Maximize	 0 100
+				"C" Maximize	 0 80
+				"D" Maximize	 100 98
DestroyFunc Maximize-Func2	
AddToFunc Maximize-Func2	"M" Maximize	 100 0
+				"C" Maximize	 80 0
+				"D" Maximize	 100 98
DestroyFunc Move-or-Iconify	
AddToFunc Move-or-Iconify	I Raise
+				"M" Move
+				"D" Iconify
DestroyFunc Resize-or-Raise	
AddToFunc Resize-or-Raise	I Raise
+				"M" Resize
+				"D" Lower
DestroyFunc Resize-or-Raise2	
AddToFunc Resize-or-Raise2	"M" Raise
+				"M" Resize
+				"D" Lower
DestroyFunc Iconify-and-Raise     
AddToFunc Iconify-and-Raise     I Iconify
+                               I Raise

################## FvwmButtons button-bar ################################
#*FvwmButtonsBack bisque3
#*MainPanel: Geometry 80x18+40+4
#*MainPanel: Back SeaGreen
#*MainPanel: (Panel(down, indicator, delay 0, steps 1) 
#		PagerPanel "Module FvwmButtons PagerPanel")
#*MainPanel: Font  -*-simsun-medium-r-*-*-16-*-*-*-*-*-*-*
#*PagerPanel: Geometry 80x352
#*PagerPanel: (Swallow FvwmPager "Module FvwmPager 0 3")
#*PagerPanel: Font  -*-simsun-medium-r-*-*-16-*-*-*-*-*-*-*

########################## Icon Manager ####################################
# this FvwmIconMan setup is for swallowing in above button bar example
*FvwmIconMan*numManagers 1
*FvwmIconMan*Resolution  page
*FvwmIconMan*background  bisque3
*FvwmIconMan*foreground  black
*FvwmIconMan*font        -*-magicsong-medium-r-*-*-16-*-*-*-*-*-gb2312.1980-0
*FvwmIconMan*format      "%t"
*FvwmIconMan*action      Mouse   1 N sendcommand Focus, sendcommand "Iconify"
*FvwmIconMan*action      Mouse   2 N sendcommand "Iconify 1"
*FvwmIconMan*action      Mouse   3 N sendcommand "FvwmIdent"
*FvwmIconMan*followfocus true
*FvwmIconMan*sort        none
*FvwmIconMan*plainbutton          up black bisque3
*FvwmIconMan*selectbutton         down black bisque3
*FvwmIconMan*focusbutton          up yellow firebrick
*FvwmIconMan*focusandselectButton down yellow firebrick
*FvwmIconMan*dontshow icon=Untitled
#*FvwmIconMan*drawicons true
*FvwmIconMan*buttongeometry  300x0
*FvwmIconMan*managergeometry 1x5

########################## Window-Identifier ###############################
# Just choose colors and a fonts
*FvwmIdentBack MidnightBlue
*FvwmIdentFore Yellow
*FvwmIdentFont  -*-simsun-medium-r-*-*-14-*-*-*-*-*-*-*

########################### Pager #########################################
*FvwmPager: Geometry 150x150+1121+845
*FvwmPager: UseSkipList
*FvwmPager: Rows 4
*FvwmPager: Columns 1
*FvwmPagerBack #908090
*FvwmPagerFore #484048
*FvwmPager:Font  -*-simsun-medium-r-*-*-14-*-*-*-*-*-*-*
*FvwmPagerHilight #cab3ca
*FvwmPagerLabel 0 Main
*FvwmPagerLabel 1 Internet
*FvwmPagerLabel 2 Program
*FvwmPagerLabel 3 Amusement
*FvwmPager:SmallFont  -*-simsun-medium-r-*-*-12-*-*-*-*-*-*-*
*FvwmPagerBalloons            All
*FvwmPagerBalloonBack         Yellow
*FvwmPagerBalloonFore         Black
*FvwmPager:BalloonFont         -*-simsun-medium-r-*-*-14-*-*-*-*-*-*-*
*FvwmPagerBalloonYOffset      +2
*FvwmPagerBalloonBorderWidth  1
*FvwmPagerBalloonBorderColor  Black

##########################FvwmWinList##################################
*FvwmWinListBack #908090
*FvwmWinListFore Black
*FvwmWinListFont  -*-simsun-medium-r-*-*-14-*-*-*-*-*-*-*
*FvwmWinListAction Click1 Iconify -1,Focus
*FvwmWinListAction Click2 Iconify
*FvwmWinListAction Click3 Module "FvwmIdent" FvwmIdent
*FvwmWinListUseSkipList
*FvwmWinListGeometry +0-1
                                      

#for FvwmBacker
*FvwmBackerDesk 0 -solid steelblue
*FvwmBackerDesk 1 -solid midnightblue

#for FvwmScroll
*FvwmScrollBack grey40
*FvwmScrollFore green
	
*FvwmAnimate: Delay 25
*FvwmAnimate: Effect Random
*FvwmAnimate: Width 3

Style FvwmTaskBar HandleWidth 0, BorderWidth 0
*FvwmTaskBar: UseSkipList
*FvwmTaskBar: AutoStick
*FvwmTaskBar: DeskOnly
#*FvwmTaskBar: Action Click1 DeiconifyRaiseAndFocus
*FvwmTaskBar: Action Click2 Iconify On
*FvwmTaskBar: Action Click3 Lower
#*FvwmTaskBar: Action Click3 FvwmIdent
*FvwmTaskBar: BellVolume 30
*FvwmTaskBar: MailCommand Exec exec rxvt -e mutt
*FvwmTaskBar: 3DFvwm
*FvwmTaskBar: StartName FVWM
*FvwmTaskBar: StartMenu RootMenu
*FvwmTaskBar: Font  -*-simsun-medium-r-*-*-14-*-*-*-*-*-*-*
#*FvwmTaskBar: Font  "xft:Luxi Mono"
*FvwmTaskBar: SelFont  -*-simsun-medium-r-*-*-14-*-*-*-*-*-*-*
*FvwmTaskBar: ShowTips
*FvwmTaskBar: ClockFormat 
*FvwmTaskBar: WindowButtonsRightMargin 20 

*FvwmTaskBar: Back seagreen
*FvwmTaskBar: Fore gold2
*FvwmTaskBar: FocusFore cornsilk
*FvwmTaskBar: IconBack darkgreen
*FvwmTaskBar: IconFore white
*FvwmTaskBar: StartCommand(Mouse 3) Popup RightKeyMenu 

#*FvwmTaskBar: Button Title hello, Icon mini.x.xpm, Action (Mouse 1) Module FvwmConsole
#*FvwmTaskBar: DateFormat "%A, %B %d, %Y"
#*FvwmTaskBar: WindowButtonsLeftMargin 20
#*FvwmTaskBar: HighlightFocus
#*FvwmTaskBar: AutoHide 6

Read fvwm.strokes

正在一步一步改良!

我的debian下安装 spb16.3的经历

网上大多数都是在redhat系列机器的安装的,我始终不成功:

整了好几天总算能启动了:

额外的安装步骤如下:

        1.安装csh,ksh

        2.

cd /usr
ln -s /tmp tmp

       3.

cd /bin
ln -s /usr/bin/basename basename

       4.将教程中的

./pubkey -d cdslmd -y

改成

./pubkey -d cdslmd -fy

       剩下的参看:http://www.isspy.com/opensuse13%E4%B8%8B%E5%AE%89%E8%A3%85-cadence-allegro-spb-16-30-000/

      教程