• 售前

  • 售后

热门帖子
入门百科

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

[复制链接]
123457848 显示全部楼层 发表于 2021-10-25 19:34:38 |阅读模式 打印 上一主题 下一主题
前言
关于TCP服务器最大并发毗连数有一种误解就是“因为端标语上限为65535,以是TCP服务器理论上的可承载的最大并发毗连数也是65535”。
先说结论:对于TCP服务端进程来说,他可以同时毗连的客户端数量并不受限于可用端标语。并发毗连数受限于linux可打开文件数,这个数是可以设置的,可以非常大,以是实际上受限于体系性能。
现在做服务器开发不加上高并发根本没脸出门,以是为了以后吹水被别人怼“天天进步并发,你本身实现的最高并发是多少”的时候能义正言辞的怼归去,趁着元旦在家没事决定本身写个demo搞一搞。
这个测试重要是想搞明确Linux下哪些参数设置限定了毗连数的最大值,上限是多少。
一、先说下demo的思路:

服务端用epoll实现,就是简简单单的吸收毗连,然后客户端用go的goroutine,每个goroutine就是简单的创建毗连,然后什么也不做。
上代码:
server:
  1. /*
  2. * g++ -o test_epoll ./test_epoll.c
  3. */
  4. #include <unistd.h>
  5. #include <sys/types.h>
  6. #include <sys/socket.h>
  7. #include <sys/epoll.h>
  8. #include <netinet/in.h>
  9. #include <arpa/inet.h>
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <errno.h>
  14. int SetReuseAddr(int fd)
  15. {
  16. int optval = 1;
  17. socklen_t optlen = sizeof(optval);
  18. return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, optlen);
  19. }
  20. int main()
  21. {
  22. int fd = socket(AF_INET, SOCK_STREAM, 0);
  23. int iRet = SetReuseAddr(fd);
  24. if (iRet != 0)
  25. {
  26. printf("setsockopt for SO_REUSEADDR failed, error:%s\n", strerror(iRet));
  27. return iRet;
  28. }
  29. struct sockaddr_in addr;
  30. memset(&addr, 0, sizeof(addr));
  31. addr.sin_family = AF_INET;
  32. addr.sin_port = htons(8080);
  33. addr.sin_addr.s_addr = INADDR_ANY;
  34. if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1)
  35. {
  36. printf("bind failed, error:%s\n", strerror(errno));
  37. return errno;
  38. }
  39. if (listen(fd, 5) == -1)
  40. {
  41. printf("listen failed, error:%s\n", strerror(errno));
  42. return errno;
  43. }
  44. printf("Listening on 8080...\n");
  45. int epfd = epoll_create(102400);
  46. struct epoll_event event;
  47. event.events = EPOLLIN;
  48. event.data.fd = fd;
  49. epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event);
  50. struct epoll_event revents[102400];
  51. int iOnline = 0;
  52. while (1)
  53. {
  54. int num = epoll_wait(epfd, revents, 102400, 60 * 1000);
  55. printf("epoll_wait return %d\n", num);
  56. if (num > 0)
  57. {
  58.   for (int i = 0; i < num; i++)
  59.   {
  60.   if (revents[i].data.fd == fd)
  61.   {
  62.    int client;
  63.    struct sockaddr_in cli_addr;
  64.    socklen_t cli_addr_len = sizeof(cli_addr);
  65.    client = accept(fd, (struct sockaddr*)&cli_addr, &cli_addr_len);
  66.    if (client == -1)
  67.    {
  68.    printf("accept failed, error:%s\n", strerror(errno));
  69.    if (errno == EMFILE)
  70.    {
  71.     printf("per-process limit reached\n");
  72.     exit(errno);
  73.    }
  74.    if (errno == ENFILE)
  75.    {
  76.     printf("system-wide limit reached\n");
  77.     exit(errno);
  78.    }
  79.    continue;
  80.    }
  81.    iOnline++;
  82.    printf("Receive a new connection from %s:%d\n", inet_ntoa(cli_addr.sin_addr), cli_addr.sin_port);
  83.    event.events = EPOLLIN;
  84.    event.data.fd = client;
  85.    epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event);
  86.   }
  87.   }
  88. }
  89. printf("Online number:%d\n", iOnline);
  90. }
  91. return 0;
  92. }
复制代码
client:
  1. package main
  2. import (
  3. "net"
  4. "fmt"
  5. "time"
  6. "strconv"
  7. "runtime"
  8. )
  9. func Connect(host string, port int) {
  10. _, err := net.Dial("tcp", host+":"+strconv.Itoa(port))
  11. if err != nil {
  12. fmt.Printf("Dial to %s:%d failed\n", host, port)
  13. return
  14. }
  15. for {
  16. time.Sleep(30 * 1000 * time.Millisecond)
  17. }
  18. }
  19. func main() {
  20. count := 0
  21. for {
  22. go Connect("192.168.63.128", 8080)
  23. count++;
  24. fmt.Printf("Gorutue num:%d\n", runtime.NumGoroutine())
  25. time.Sleep(100 * time.Millisecond)
  26. }
  27. }
复制代码
二、开始测试

第一次:

先说效果,毗连数到达1031时accept失败了,其时还没有对errno做判定,以是只打印输出了accept失败。

然后首先想到的是ulimit -n的限定,查看了一下,默认值1024,然后就是修改这个值,在/etc/security/limits.conf中添加一下内容:
  1. 1 * soft nofile 102400
  2. 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这么牛逼的机制,才使得我们现在想实现高并发是如此的容易,渴望本身有一天也能这么牛逼,哈哈。
总结
以上就是这篇文章的全部内容了,渴望本文的内容对大家的学习或者工作具有一定的参考学习价值,假如有疑问大家可以留言交换,谢谢大家对脚本之家的支持。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

帖子地址: 

回复

使用道具 举报

分享
推广
火星云矿 | 预约S19Pro,享500抵1000!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

草根技术分享(草根吧)是全球知名中文IT技术交流平台,创建于2021年,包含原创博客、精品问答、职业培训、技术社区、资源下载等产品服务,提供原创、优质、完整内容的专业IT技术开发社区。
  • 官方手机版

  • 微信公众号

  • 商务合作