如何测试Linux下tcp最大连接数限制详解

前言

关于TCP服务器最大并发连接数有一种误解就是“因为端口号上限为65535,所以TCP服务器理论上的可承载的最大并发连接数也是65535”。

先说结论:对于TCP服务端进程来说,他可以同时连接的客户端数量并不受限于可用端口号。并发连接数受限于linux可打开文件数,这个数是可以配置的,可以非常大,所以实际上受限于系统性能。

现在做服务器开发不加上高并发根本没脸出门,所以为了以后吹水被别人怼“天天提高并发,你自己实现的最高并发是多少”的时候能义正言辞的怼回去,趁着元旦在家没事决定自己写个demo搞一搞。

这个测试主要是想搞明白Linux下哪些参数配置限制了连接数的最大值,上限是多少。

一、先说下demo的思路:

服务端用epoll实现,就是简简单单的接收连接,然后客户端用go的goroutine,每个goroutine就是简单的建立连接,然后什么也不做。

上代码:

server:

/*
 * g++ -o test_epoll ./test_epoll.c
 */
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int SetReuseAddr(int fd)
{
 int optval = 1;
 socklen_t optlen = sizeof(optval);
 return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, optlen);
}

int main()
{
 int fd = socket(AF_INET, SOCK_STREAM, 0);
 int iRet = SetReuseAddr(fd);
 if (iRet != 0)
 {
 printf("setsockopt for SO_REUSEADDR failed, error:%s\n", strerror(iRet));
 return iRet;
 }

 struct sockaddr_in addr;
 memset(&addr, 0, sizeof(addr));
 addr.sin_family = AF_INET;
 addr.sin_port = htons(8080);
 addr.sin_addr.s_addr = INADDR_ANY;
 if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1)
 {
 printf("bind failed, error:%s\n", strerror(errno));
 return errno;
 }

 if (listen(fd, 5) == -1)
 {
 printf("listen failed, error:%s\n", strerror(errno));
 return errno;
 }
 printf("Listening on 8080...\n");

 int epfd = epoll_create(102400);
 struct epoll_event event;
 event.events = EPOLLIN;
 event.data.fd = fd;
 epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event);

 struct epoll_event revents[102400];
 int iOnline = 0;
 while (1)
 {
 int num = epoll_wait(epfd, revents, 102400, 60 * 1000);
 printf("epoll_wait return %d\n", num);
 if (num > 0)
 {
  for (int i = 0; i < num; i++)
  {
  if (revents[i].data.fd == fd)
  {
   int client;
   struct sockaddr_in cli_addr;
   socklen_t cli_addr_len = sizeof(cli_addr);
   client = accept(fd, (struct sockaddr*)&cli_addr, &cli_addr_len);
   if (client == -1)
   {
   printf("accept failed, error:%s\n", strerror(errno));
   if (errno == EMFILE)
   {
    printf("per-process limit reached\n");
    exit(errno);
   }
   if (errno == ENFILE)
   {
    printf("system-wide limit reached\n");
    exit(errno);
   }
   continue;
   }

   iOnline++;
   printf("Receive a new connection from %s:%d\n", inet_ntoa(cli_addr.sin_addr), cli_addr.sin_port);
   event.events = EPOLLIN;
   event.data.fd = client;
   epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event);
  }
  }
 }
 printf("Online number:%d\n", iOnline);
 }

 return 0;
}

client:

package main

import (
 "net"
 "fmt"
 "time"
 "strconv"
 "runtime"
)

func Connect(host string, port int) {
 _, err := net.Dial("tcp", host+":"+strconv.Itoa(port))
 if err != nil {
 fmt.Printf("Dial to %s:%d failed\n", host, port)
 return
 }

 for {
 time.Sleep(30 * 1000 * time.Millisecond)
 }
}

func main() {
 count := 0
 for {
 go Connect("192.168.63.128", 8080)
 count++;
 fmt.Printf("Gorutue num:%d\n", runtime.NumGoroutine())
 time.Sleep(100 * time.Millisecond)
 }
}

二、开始测试

第一次:

先说结果,连接数达到1031时accept失败了,当时还没有对errno做判断,所以只打印输出了accept失败。

然后首先想到的是ulimit -n的限制,查看了一下,默认值1024,然后就是修改这个值,在/etc/security/limits.conf中添加一下内容:

1 * soft nofile 102400
2 * hard nofile 102400

然后关闭当前xshell连接,重新连接即生效,现在看ulimit -n就是102400了。

这两行的意思就是将每个进程能打开的文件描述符个数的soft、hard限制调整为102400,

注:ulimit -n 102400也可以生效,但是这个修改是临时的。

然后进行第二次测试。

第二次:

逗比了,其实连接数只有2000+,我之前还在奇怪为啥Windows的默认连接数能有这么高呢,原来有些连接已经断了,但是因为我没有做处理,所以以为还在呢,看来我得再安装一个虚拟机了[二哈]

待继续。。。

安装虚拟机去,

时间:2017-12-31 00:09:00

虚拟机安装好了,接着搞,

这次是真的超过10K了。

连接数还在增加,不知道能不能最终达到10万呢,小小的期待ing

时间:2017-12-31 00:41:00,最终上限卡在28232,golang一直报dial失败,由于忘了打印出具体错误信息了,所以无从知道为什么dial失败,所以只能再跑一次T_T

时间:2017-12-31 01:01:00,添加打印dial失败的错误信息的,又跑了一遍,还是在28232时出现dial失败,错误信息:

golang的标准库文档中么有对错误信息的解释,从错误信息来看,是分配地址失败,于是想是不是端口地址范围限制了。

查看了一下端口地址范围,确认就是这个限制,由于端口地址是16位,所以,就算把这个端口地址范围修改为1024--65535,也最多能开启64521个连接,而我现在只有一台虚拟机作为客户端,所以想要实现10万连接是不可能了,但是通过这次测试,也让我搞明白了,到底哪些参数会限制连接的上限,这就是我想要的。

最后,感谢Linux内核团队的大神们推出了epoll这么牛逼的机制,才使得我们现在想实现高并发是如此的容易,希望自己有一天也能这么牛逼,哈哈。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • linux上TCP connection timeout问题解决办法

     linux上TCP connection timeout问题解决办法 最近在产线上经常出现connection timeout的问题,先看看Java 中关于connection timeout 的异常如何产生 JAVA中的timeout java.net.SocketTimeoutException: connect timed out 客户端异常:connect timed out at java.net.PlainSocketImpl.socketConnect(Native Method

  • 详解Linux系统如何防止TCP洪水攻击

    #最关键参数,默认为5,修改为0 表示不要重发 net.ipv4.tcp_synack_retries = 0 #半连接队列长度 net.ipv4.tcp_max_syn_backlog = 200000 #系统允许的文件句柄的最大数目,因为连接需要占用文件句柄 fs.file-max = 819200 #用来应对突发的大并发connect 请求 net.core.somaxconn = 65536 #最大的TCP 数据接收缓冲(字节) net.core.rmem_max = 102412300

  • linux下2个检查tcp连接的命令

    1 检测web服务器的链接数量及状态: netstat -ant|awk '{print $5 "\t" $6}'|grep "::ffff:"|sed -e 's/::ffff://' -e 's/:[0-9]*//' |sort|uniq -c| sort -rn|head -10 结果: 122 125.162.71.199 TIME_WAIT 99 79.119.125.43 TIME_WAIT 81 125.167.243.77 TIME_WAIT 75

  • 如何测试Linux下tcp最大连接数限制详解

    前言 关于TCP服务器最大并发连接数有一种误解就是"因为端口号上限为65535,所以TCP服务器理论上的可承载的最大并发连接数也是65535". 先说结论:对于TCP服务端进程来说,他可以同时连接的客户端数量并不受限于可用端口号.并发连接数受限于linux可打开文件数,这个数是可以配置的,可以非常大,所以实际上受限于系统性能. 现在做服务器开发不加上高并发根本没脸出门,所以为了以后吹水被别人怼"天天提高并发,你自己实现的最高并发是多少"的时候能义正言辞的怼回去,趁着

  • Linux下安装mysql的教程详解

    1. 关闭mysql服务 # service mysqld stop 2. 检查是否有rpm包,如果没有用rpm安装过mysql,不应该有残留,如果有,需要删掉 检查语法: rpm -qa|grep -i mysql 删除语法: rpm -e <包的名字> 如果遇到依赖,无法删除,使用 rpm -e --nodeps <包的名字> 不检查依赖,直接删除rpm包. 3. 通过find命令检查是否有安装mysql文件,有需要删除 检查语法: find / -name mysql 删除语

  • Linux 下读XML 的类详解及实现代码

     Linux 下读XML 的类详解及实现代码 在Linux下写程序,常需要读一些配置文件.现有的XML工具很多,可以方便的编辑和生成XML. 但VC中用的XML解析器在Linux下不能用.只好自已写了个.用了一下,还不错. #include <stdio.h> #include <stdlib.h> // ********************************************************************** // // XML解析类(hongh

  • linux下用户程序同内核通信详解(netlink机制)

    简介 linux下用户程序同内核通信的方式一般有ioctl, proc文件系统,剩下一个就是Netlink套接字了. 这里先介绍下netlink. Netlink 是一种在内核与用户应用间进行双向数据传输的非常好的方式,用户态应用使用标准的 socket API 就可以使用 netlink 提供的强大功能,内核态需要使用专门的内核 API 来使用 netlink. Netlink 相对于系统调用,ioctl 以及 /proc 文件系统而言具有以下优点: 1,为了使用 netlink,用户仅需要在

  • linux下安装solr的教程详解

    安装Solr 第一步:将solr的压缩包上传到Linux系统 第二步:解压tomcat tar -zvxf apache-tomcat-7.0.47.tar.gz [root@localhost ~]# tar -zxvf apache-tomcat-7.0.47.tar.gz 第三步:在/usr/local/新建目录solr 第四步:将tomcat拷贝在/usr/local/solr/目录下,并命名为tomcat 第五步 解压solr [root@localhost ~]# tar -zvxf

  • Linux下的fdisk命令用法详解

    Linux下的fdisk功能是极其强大的,用它可以划分出最复杂的分区,下面简要介绍一下它的用法: 对于IDE硬盘,每块盘有一个设备名:对应于主板的四个IDE接口,设备名依次为:/dev/hda,/dev/hdb,/dev/hdc,/dev/hdd等, 如果还有IDE Raid卡,则依次为:/dev/hde,/dev/hdf,/dev/hdg,/dev/hdh.对于SCSI硬盘,则设备名依次为/dev/sda,/dev/sdb...等等 fdisk的命令行用法为: fdisk 硬盘设备名 进入fd

  • Linux下重新启动Tomcat的步骤详解

    本文主要介绍的是Linux下重新启动Tomcat的步骤,在Linux系统下,重启Tomcat使用命令操作的! 具体的步骤如下: 首先,进入Tomcat下的bin目录 cd /usr/local/tomcat/bin 使用Tomcat关闭命令 ./shutdown.sh 查看Tomcat是否以关闭 ps -ef|grep java 如果显示以下相似信息,说明Tomcat还没有关闭 root 7010 1 0 Apr19 ? 00:30:13 /usr/local/java/bin/java -Dj

  • linux下配置yum源方法详解

    本人使用的方法一,成功配置,方法二没测过,可以作为参考 方法一: 1.确保RHEL5中已经安装了yum [root@lvs-master ~]# rpm -qa |grep yum yum-metadata-parser-2-el5 yum-updatesd-9-el5 yum-22-el5 yum-security-16-el5 yum-rhn-plugin-4-el5 2.修改源配置文件 #vim /etc/yum.repos.d/CentOS-Base.repo (如果目录下没有.repo

  • linux下python中文乱码解决方案详解

    1. 场景描述 linux服务器下安装了Anaconda3,执行Pyhton的K-means算法,结果出现如下图的中文字符乱码.上次已经解决了,忘记记录解决流程了,这次配置了一台新的服务器,又出现,默认不配置的话matplotlib画图就会乱码,这次把解决过程记录下,希望能帮助自己和有需要的朋友. 2. 解决方案 网上有好几个解决方案,只介绍自己实战可行的. 1. 查看matplotlib字体位置 python import matplotlib print(matplotlib.matplot

  • Linux下alias命令的用法详解

    1.alias的使用 alias命令用来设置指令的别名.我们可以使用该命令可以将一些较长的命令进行简化. 用alias 短命令='原命令 选项' alias 138ssh= 'ssh -i ~/.ssh/138.pem ec2-user@192.168.21.138' 这下子就可以直接使用138ssh 来代替原来ssh -i ~/.ssh/138.pem ec2-user@192.168.21.138 查看当前所有的alias alias-p 删除一个alias unalias 命令 然后我就开

随机推荐