高并发服务器开发与配置( 二 )


第一步 , 修改/etc/security/limits.conf文件 , 在文件中添加如下行:speng soft nofile 10240speng hard nofile 10240其中speng指定了要修改的用户的用户名 , 可用'*'号表示修改所有用户的限制;soft或hard指定要修改软限制还是硬限制;10240则指定了想要修改的新的限制值 , 即最大打开文件数(请注意软限制值要小于或等于硬限制) 。修改完后保存文件 。
第二步 , 修改/etc/pam.d/login文件 , 在文件中添加如下行:session required 
/lib/security/pam_limits.so 这是告诉Linux在用户完成系统登录后 , 应该调用pam_limits.so模块来设置系统对该用户可使用的各种资源数量的最大限制(包括用户可打开的最大文件数限制) , 而pam_limits.so模块就会从/etc/security/limits.conf文件中读取配置来设置这些限制值 。修改完后保存此文件 。
第三步 , 查看Linux系统级的最大打开文件数限制-硬限制 , 使用如下命令:[speng@as4 ~]$ cat 
/proc/sys/fs/file-max12158这表明这台Linux系统最多允许同时打开(即包含所有用户打开文件数总和)12158个文件 , 是Linux系统级硬限制 , 所有用户级的打开文件数限制都不应超过这个数值 。通常这个系统级硬限制是Linux系统在启动时根据系统硬件资源状况计算出来的最佳的最大同时打开文件数限制 , 如果没有特殊需要 , 不应该修改此限制 , 除非想为用户级打开文件数限制设置超过此限制的值 。修改此硬限制的方法是修改/etc/rc.local脚本 , 在脚本中添加如下行:echo 22158 > /proc/sys/fs/file-max这是让Linux在启动完成后强行将系统级打开文件数硬限制设置为22158.修改完后保存此文件 。
第四步 , 完成上述步骤后重启系统 , 一般情况下就可以将Linux系统对指定用户的单一进程允许同时打开的最大文件数限制设为指定的数值 。如果重启后用 ulimit-n命令查看用户可打开文件数限制仍然低于上述步骤中设置的最大值 , 这可能是因为在用户登录脚本/etc/profile中使用ulimit -n命令已经将用户可同时打开的文件数做了限制 。由于通过ulimit-n修改系统对用户可同时打开文件的最大数限制时 , 新修改的值只能小于或等于上次 ulimit-n设置的值 , 因此想用此命令增大这个限制值是不可能的 。所以 , 如果有上述问题存在 , 就只能去打开/etc/profile脚本文件 , 在文件中查找是否使用了ulimit-n限制了用户可同时打开的最大文件数量 , 如果找到 , 则删除这行命令 , 或者将其设置的值改为合适的值 , 然后保存文件 , 用户退出并重新登录系统即可 。通过上述步骤 , 就为支持高并发TCP连接处理的通讯处理程序解除关于打开文件数量方面的系统限制 。
2、修改网络内核对TCP连接的有关限制
在Linux上编写支持高并发TCP连接的客户端通讯处理程序时 , 有时会发现尽管已经解除了系统对用户同时打开文件数的限制 , 但仍会出现并发TCP连接数增加到一定数量时 , 再也无法成功建立新的TCP连接的现象 。出现这种现在的原因有多种 。
第一种原因可能是因为Linux网络内核对本地端口号范围有限制(客户端能使用的端口号限制) 。此时 , 进一步分析为什么无法建立TCP连接 , 会发现问题出在connect()调用返回失败 , 查看系统错误提示消息是"Can't assign requestedaddress".同时 , 如果在此时用tcpdump工具监视网络 , 会发现根本没有TCP连接时客户端发SYN包的网络流量 。这些情况说明问题在于本地Linux系统内核中有限制 。其实 , 问题的根本原因在于Linux内核的TCP/IP协议实现模块对系统中所有的客户端TCP连接对应的本地端口号的范围进行了限制(例如 , 内核限制本地端口号的范围为1024~32768之间) 。当系统中某一时刻同时存在太多的TCP客户端连接时 , 由于每个TCP客户端连接都要占用一个唯一的本地端口号(此端口号在系统的本地端口号范围限制中) , 如果现有的TCP客户端连接已将所有的本地端口号占满(端口耗尽) , 因此系统会在这种情况下在connect()调用中返回失败 , 并将错误提示消息设为"Can't assignrequested address".有关这些控制逻辑可以查看Linux内核源代码 , 以linux2.6内核为例 , 可以查看tcp_ipv4.c文件中如下函数:static int tcp_v4_hash_connect(struct sock *sk)请注意上述函数中对变量sysctl_local_port_range的访问控制 。变量sysctl_local_port_range的初始化则是在tcp.c文件中的如下函数中设置:void __init tcp_init(void)内核编译时默认设置的本地端口号范围可能太小 , 因此需要修改此本地端口范围限制 , 方法为


推荐阅读