首页 > 其他分享 >单机10万TCP连接测试记录

单机10万TCP连接测试记录

时间:2023-10-10 15:14:24浏览次数:41  
标签:count 10 tcpClient 单机 TCP using new config IPHost

转自:https://www.cnblogs.com/fuhua/p/16904864.html

单机10万TCP连接测试记录 

目录

 

前言

现有两台Ubuntu服务器,一台名叫TcpServer,一台名叫TcpClient。
TcpServer用于监听Tcp连接,TcpClient用于发起Tcp连接。
现在想测试TcpServer是否能承受住10w+ TCP连接。

编程语言:C#
使用框架:TouchSocket

准备工作

安装DotNet6环境

请查看:Ubuntu 安装DotNet6步骤

服务端代码

using System.Text;
using TouchSocket.Core.Config;
using TouchSocket.Core.Dependency;
using TouchSocket.Core.Log;
using TouchSocket.Sockets;

namespace TcpServer
{
    internal class Program
    {
        //用于记录客户端数量
        private static int _count = 0;
        //阻塞事件,防止客户端退出
        private static readonly AutoResetEvent _closingEvent = new AutoResetEvent(false);
        static void Main(string[] args)
        {
            TcpService service = new TcpService();
            service.Connected += (client, e) => 
            {
                Interlocked.Increment(ref _count);
                Console.WriteLine($"有客户端连接:{((SocketClient)client).GetIPPort()} ---- 客户端数量:{_count}");
            
            };
            service.Disconnected += (client, e) => 
            {
                Interlocked.Decrement(ref _count);
                Console.WriteLine($"有客户断开:{((SocketClient)client).GetIPPort()} ---- 客户端数量:{_count}");
            };
            service.Setup( new TouchSocketConfig()
                .SetListenIPHosts(new IPHost[] {new IPHost(7790) })
                .SetMaxCount(999999)
                //这里很重要,否则一分钟后服务端会删除无活动的连接
                .SetClearInterval(-1))
                .Start();

            _closingEvent.WaitOne();
        }
    }
}

客户端代码

using System.Net.Sockets;
using System.Text;
using TouchSocket.Core.Config;
using TouchSocket.Sockets;

namespace TestTcpClient
{
    internal class Program
    {
        //用于记录连接数量
        private static int _count = 0;
        private static readonly AutoResetEvent _closingEvent = new AutoResetEvent(false);
        static void Main(string[] args)
        {
            for (int i = 0; i < 100000; i++)
            {
                try
                {
                    TouchSocket.Sockets.TcpClient tcpClient = new TouchSocket.Sockets.TcpClient();
                    tcpClient.Connected += (client, e) => 
                    {
                        Interlocked.Increment(ref _count);
                        Console.WriteLine($"当前连接数:{_count}");
                    };
                    tcpClient.Disconnected += (client, e) => 
                    {
                        Interlocked.Decrement(ref _count);
                        Console.WriteLine($"当前连接数:{_count}");
                    };
                    tcpClient.Setup("1.14.107.247:7790");
                    tcpClient.Connect();
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"{i}:{ex.Message}");
                    if(ex.InnerException != null)
                    {
                        Console.WriteLine($"{i}:{ex.InnerException.Message}");
                    }
                }
            }
            _closingEvent.WaitOne();  
        }
    }
}

编译

将TcpServer和TcpClient编译后分别放入TcpServer服务器和TcpClient服务器

测试记录

失败尝试1(Linux可用端口范围限制)

运行TcpServer:dotnet TcpServer.dll
运行TcpClient:dotnet TestTcpClient.dll

从服务端记录可以看到,客户端数量在28232时候不再增加了

客户端疯狂抛出异常 The Operation has timed out

上述原因是因为TcpClient服务器限制了端口范围

解决Linux端口范围限制

查看端口范围

#查看端口范围
sysctl net.ipv4.ip_local_port_range

可以看到端口范围在32768到60999之间
60999-32768=28231 正好印证了我们的猜想

修改端口范围

vim /etc/sysctl.conf

追加记录
net.ipv4.ip_local_port_range = 1024 65535

需要注意的是1024之前是系统保留端口,开始值不能小于1024,结束值不能大于65535否则会报错

保存后使用sysctl -p使修改立即生效

sysctl -p

再次使用命令sysctl net.ipv4.ip_local_port_range查看端口范围

sysctl net.ipv4.ip_local_port_range

可以看到刚才的设置成功了

失败尝试2(可用端口耗尽)

再次运行TcpServer:dotnet TcpServer.dll
再次运行TcpClient:dotnet TestTcpClient.dll

这次明显有了改善,从服务端记录可以看到,客户端数量在64511时候不再增加了

客户端依旧疯狂报错:the operation has timed out

这次的问题依旧在客户端,不过和上一次失败不太一样,上次是被Linux可用端口范围限制了,这次是真的把客户端端口耗尽了。

而我们的目标是单机10w连接,得想办法突破客户端65535端口数限制。

我们知道TCP协议由四元组组成,任何一个改变都视为一个新的连接:

<Server 端口><Client 端口>

所以我们有两种方案实现单机10W连接

方案一、改变 Server 端口
方案二、改变 Client IP

方案一、改变Server端口

当服务端监听7791端口时,客户端允许分配65535个端口建立连接
当服务端监听7792端口时,客户端将再次允许分配65535个端口建立连接
所以我们只需要对TcpServer代码进行改造增加监听端口即可.

修改TcpServer代码

TcpServer代码如下,监听7791 7792 7793三个端口

using System.Text;
using TouchSocket.Core.Config;
using TouchSocket.Core.Dependency;
using TouchSocket.Core.Log;
using TouchSocket.Sockets;

namespace TcpServer
{
    internal class Program
    {
        //用于记录客户端数量
        private static int _count = 0;
        //阻塞事件,防止客户端退出
        private static readonly AutoResetEvent _closingEvent = new AutoResetEvent(false);
        static void Main(string[] args)
        {
            TcpService service = new TcpService();
            service.Connected += (client, e) => 
            {
                Interlocked.Increment(ref _count);
                Console.WriteLine($"有客户端连接:{client.GetIPPort()} 目标端口:{client.ServicePort} ---- 客户端数量:{_count}");
            
            };
            service.Disconnected += (client, e) => 
            {
                Interlocked.Decrement(ref _count);
                Console.WriteLine($"有客户断开:{client.GetIPPort()} ---- 客户端数量:{_count}");
            };
            service.Setup( new TouchSocketConfig()
                .SetListenIPHosts(new IPHost[] {new IPHost(7791), new IPHost(7792), new IPHost(7793) })
                .SetMaxCount(999999)
                //这里很重要,否则一分钟后服务端会删除无活动的连接
                .SetClearInterval(-1))
                .Start();

            _closingEvent.WaitOne();
        }
    }
}

修改TcpClient代码

using System.Net.Sockets;
using System.Text;
using TouchSocket.Core.Config;
using TouchSocket.Sockets;

namespace TestTcpClient
{
    internal class Program
    {
        //用于记录连接数量
        private static int _count = 0;
        private static readonly AutoResetEvent _closingEvent = new AutoResetEvent(false);
        static void Main(string[] args)
        {
            for (int i = 1; i <= 120000; i++)
            {
                try
                {
                    TouchSocket.Sockets.TcpClient tcpClient = new TouchSocket.Sockets.TcpClient();
                    tcpClient.Connected += (client, e) =>
                    {
                        Interlocked.Increment(ref _count);
                        Console.WriteLine($"当前连接数:{_count}");
                    };
                    tcpClient.Disconnected += (client, e) =>
                    {
                        Interlocked.Decrement(ref _count);
                        Console.WriteLine($"当前连接数:{_count}");
                    };
                    if (i <= 40000)
                    {
                        tcpClient.Setup("1.14.107.247:7791");
                    }
                    if (i > 40000)
                    {
                        tcpClient.Setup("1.14.107.247:7792");
                    }
                    if (i > 80000)
                    {
                        tcpClient.Setup("1.14.107.247:7793");
                    }
                    tcpClient.Connect();
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"{i}:{ex.Message}");
                    if (ex.InnerException != null)
                    {
                        Console.WriteLine($"{i}:{ex.InnerException.Message}");
                    }
                }
            }
            _closingEvent.WaitOne();
        }
    }
}

再次测试(完成目标)

注意:如果您测试发现创建不了10w+连接,大概率是服务器内存满了,可以尝试加大服务器内存或者降低每个连接缓冲区大小

进阶测试(测试TCP连接上限)

服务端代码

using System.Text;
using TouchSocket.Core.Config;
using TouchSocket.Core.Dependency;
using TouchSocket.Core.Log;
using TouchSocket.Sockets;

namespace TcpServer
{
    internal class Program
    {
        //用于记录客户端数量
        private static int _count = 0;
        //阻塞事件,防止客户端退出
        private static readonly AutoResetEvent _closingEvent = new AutoResetEvent(false);
        static void Main(string[] args)
        {
            TcpService service = new TcpService();
            service.Connected += (client, e) => 
            {
                Interlocked.Increment(ref _count);
                Console.WriteLine($"有客户端连接:{client.GetIPPort()} 目标端口:{client.ServicePort} ---- 客户端数量:{_count}");
            
            };
            service.Disconnected += (client, e) => 
            {
                Interlocked.Decrement(ref _count);
                Console.WriteLine($"有客户断开:{client.GetIPPort()} ---- 客户端数量:{_count}");
            };
            service.Setup( new TouchSocketConfig()
                .SetListenIPHosts(new IPHost[] {
                    new IPHost(7790),
                    new IPHost(7791), 
                    new IPHost(7792), 
                    new IPHost(7793),
                    new IPHost(7794),
                    new IPHost(7795),
                    new IPHost(7796),
                    new IPHost(7797),
                    new IPHost(7798),
                    new IPHost(7799),
                    new IPHost(7780),
                    new IPHost(7781),
                    new IPHost(7782),
                    new IPHost(7783),
                    new IPHost(7784),
                    new IPHost(7785),
                    new IPHost(7786),
                    new IPHost(7787),
                    new IPHost(7788),
                    new IPHost(7789),
                })
                .SetMaxCount(999999)
                //这里很重要,减少缓冲区大小防止把内存跑满了
                .SetBufferLength(64)
                //这里很重要,否则一分钟后服务端会删除无活动的连接
                .SetClearInterval(-1))
                .Start();

            _closingEvent.WaitOne();
        }
    }
}

客户端代码

using System.Net.Sockets;
using System.Text;
using TouchSocket.Core.Config;
using TouchSocket.Sockets;

namespace TestTcpClient
{
    internal class Program
    {
        //用于记录连接数量
        private static int _count = 0;
        private static readonly AutoResetEvent _closingEvent = new AutoResetEvent(false);
        static void Main(string[] args)
        {
            for (int i = 1; i <= 1000000; i++)
            {
                try
                {
                    TouchSocket.Sockets.TcpClient tcpClient = new TouchSocket.Sockets.TcpClient();
                    tcpClient.Connected += (client, e) =>
                    {
                        Interlocked.Increment(ref _count);
                        Console.WriteLine($"当前连接数:{_count}");
                    };
                    tcpClient.Disconnected += (client, e) =>
                    {
                        Interlocked.Decrement(ref _count);
                        Console.WriteLine($"当前连接数:{_count}");
                    };
                    //声明配置
                    TouchSocketConfig config = new TouchSocketConfig();
                    if (i <= 50000)
                    {
                        config.SetRemoteIPHost(new IPHost("1.14.107.247:7790")).SetBufferLength(64);
                        tcpClient.Setup(config);
                    }
                    if (i > 100000)
                    {
                        config.SetRemoteIPHost(new IPHost("1.14.107.247:7791")).SetBufferLength(64);
                        tcpClient.Setup(config);
                    }
                    if (i > 150000)
                    {
                        config.SetRemoteIPHost(new IPHost("1.14.107.247:7792")).SetBufferLength(64);
                        tcpClient.Setup(config);
                    }
                    if (i > 200000)
                    {
                        config.SetRemoteIPHost(new IPHost("1.14.107.247:7793")).SetBufferLength(64);
                        tcpClient.Setup(config);
                    }
                    if (i > 250000)
                    {
                        config.SetRemoteIPHost(new IPHost("1.14.107.247:7797")).SetBufferLength(64);
                        tcpClient.Setup(config);
                    }
                    if (i > 300000)
                    {
                        config.SetRemoteIPHost(new IPHost("1.14.107.247:7795")).SetBufferLength(64);
                        tcpClient.Setup(config);
                    }
                    if (i > 350000)
                    {
                        config.SetRemoteIPHost(new IPHost("1.14.107.247:7796")).SetBufferLength(64);
                        tcpClient.Setup(config);
                    }
                    if (i > 400000)
                    {
                        config.SetRemoteIPHost(new IPHost("1.14.107.247:7797")).SetBufferLength(64);
                        tcpClient.Setup(config);
                    }
                    if (i > 450000)
                    {
                        config.SetRemoteIPHost(new IPHost("1.14.107.247:7798")).SetBufferLength(64);
                        tcpClient.Setup(config);
                    }
                    if (i > 500000)
                    {
                        config.SetRemoteIPHost(new IPHost("1.14.107.247:7799")).SetBufferLength(64);
                        tcpClient.Setup(config);
                    }
                    if (i > 550000)
                    {
                        config.SetRemoteIPHost(new IPHost("1.14.107.247:7780")).SetBufferLength(64);
                        tcpClient.Setup(config);
                    }
                    if (i > 600000)
                    {
                        config.SetRemoteIPHost(new IPHost("1.14.107.247:7781")).SetBufferLength(64);
                        tcpClient.Setup(config);
                    }
                    if (i > 650000)
                    {
                        config.SetRemoteIPHost(new IPHost("1.14.107.247:7782")).SetBufferLength(64);
                        tcpClient.Setup(config);
                    }
                    if (i > 700000)
                    {
                        config.SetRemoteIPHost(new IPHost("1.14.107.247:7783")).SetBufferLength(64);
                        tcpClient.Setup(config);
                    }
                    if (i > 750000)
                    {
                        config.SetRemoteIPHost(new IPHost("1.14.107.247:7784")).SetBufferLength(64);
                        tcpClient.Setup(config);
                    }
                    if (i > 800000)
                    {
                        config.SetRemoteIPHost(new IPHost("1.14.107.247:7785")).SetBufferLength(64);
                        tcpClient.Setup(config);
                    }
                    if (i > 850000)
                    {
                        config.SetRemoteIPHost(new IPHost("1.14.107.247:7786")).SetBufferLength(64);
                        tcpClient.Setup(config);
                    }
                    if (i > 900000)
                    {
                        config.SetRemoteIPHost(new IPHost("1.14.107.247:7787")).SetBufferLength(64);
                        tcpClient.Setup(config);
                    }
                    if (i > 950000)
                    {
                        config.SetRemoteIPHost(new IPHost("1.14.107.247:7788")).SetBufferLength(64);
                        tcpClient.Setup(config);
                    }
                    if (i > 1000000)
                    {
                        config.SetRemoteIPHost(new IPHost("1.14.107.247:7789")).SetBufferLength(64);
                        tcpClient.Setup(config);
                    }
                    tcpClient.Connect();
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"{i}:{ex.Message}");
                    if (ex.InnerException != null)
                    {
                        Console.WriteLine($"{i}:{ex.InnerException.Message}");
                    }
                }
            }
            _closingEvent.WaitOne();
        }
    }
}

测试结果,当前配置服务器极限大概能跑364510个TCP连接

查看内核对象发现使用率基本满了

slabtop

方案二、改变ClientIP

有时服务端受限于只能监听某一个端口,不能使用方案一。
此时我们可以给TcpCient服务器绑定多个外网IP解决65535端口数限制。
比如给TcpClient服务器绑定两个外网IP,并在TcpClient服务器创建两个网卡,不同网卡走不同外网IP。
此时TcpClient只需要前60000个请求走网卡1,后60000个请求走网卡二即可实现绕过65535端口数限制。接下来实操下。

腾讯云申请弹性网卡

参考链接:https://cloud.tencent.com/document/product/576/59353#ubuntu

腾讯云申请外网ip并绑定弹性网卡

修改TcpClient代码

在服务器查看配置好的IP和网卡
局域网IP分别是172.27.0.5和172.27.0.14

接下来修改TcpClient代码

using System.Net.Sockets;
using System.Text;
using TouchSocket.Core.Config;
using TouchSocket.Sockets;

namespace TestTcpClient
{
    internal class Program
    {
        //用于记录连接数量
        private static int _count = 0;
        private static readonly AutoResetEvent _closingEvent = new AutoResetEvent(false);
        static void Main(string[] args)
        {
            for (int i = 1; i <= 1000000; i++)
            {
                try
                {
                    TouchSocket.Sockets.TcpClient tcpClient = new TouchSocket.Sockets.TcpClient();
                    tcpClient.Connected += (client, e) =>
                    {
                        Interlocked.Increment(ref _count);
                        Console.WriteLine($"当前连接数:{_count}");
                    };
                    tcpClient.Disconnected += (client, e) =>
                    {
                        Interlocked.Decrement(ref _count);
                        Console.WriteLine($"当前连接数:{_count}");
                    };
                    TouchSocketConfig config = new TouchSocketConfig();
                    if (i <= 60000)
                    {
                        config.SetRemoteIPHost(new IPHost("1.14.107.247:7790"))
                            .SetBufferLength(64)
                            //通过网卡1建立连接
                            .SetBindIPHost("172.27.0.5:0");
                        tcpClient.Setup(config);
                    }
                    if (i > 60000)
                    {
                        config.SetRemoteIPHost(new IPHost("1.14.107.247:7790"))
                            .SetBufferLength(64)
                            //通过网卡2建立连接
                             .SetBindIPHost("172.27.0.14:0");
                        tcpClient.Setup(config);
                    }
                    tcpClient.Connect();
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"{i}:{ex.Message}");
                    if (ex.InnerException != null)
                    {
                        Console.WriteLine($"{i}:{ex.InnerException.Message}");
                    }
                }
            }
            _closingEvent.WaitOne();
        }
    }
}

再次测试(完成目标)

结语

其他设置

查阅其他文章还提到修改下面的参数,
不过本文并没用到,先记录下。

vim /etc/sysctl.conf

#系统最大句柄数
fs.file-max=1100000
#最大进程数
fs.nr_open=1100000

#使设置生效
sysctl -p

vim /etc/security/limits.conf

root soft nproc 1010000
root hard nproc 1010000
root soft nofile 1010000
root hard nofile 1010000

Windows为什么不行

假如将TcpClient放到本地windows下去连接服务端。
我们会发现建立3000个左右连接就无法继续创建了,打开网页也非常卡。
初步推测是路由器防局域网病毒之类的策略导致的,后续再研究。

源码下载:

链接:https://pan.baidu.com/s/1TdmFGxv_zCDp05PQMvGSrQ?pwd=8ajf
提取码:8ajf

参考资料:
https://blog.csdn.net/zhangyanfei01/article/details/114257045
https://mp.weixin.qq.com/s/fxy4S78Xw54y0iU_HsOosA
https://blog.51cto.com/u_15060546/2641200
https://blog.csdn.net/s_zhchluo/article/details/118415011

标签:count,10,tcpClient,单机,TCP,using,new,config,IPHost
From: https://www.cnblogs.com/gzy2016Blog/p/17754714.html

相关文章

  • GBU810-ASEMI高性能整流桥GBU810
    编辑:llGBU810-ASEMI高性能整流桥GBU810型号:GBU810品牌:ASEMI封装:GBU-4恢复时间:>50ns正向电流:8A反向耐压:1000V芯片个数:4引脚数量:4类型:整流桥、功率整流器件特性:功率整流器件、高性能整流桥浪涌电流:200A正向压降:1.10V封装尺寸:如图工作温度:-55°C~150°CGBU810特性超......
  • 2023年高二10月月考21题空间直角坐标系
    ......
  • 10月9日总结
    一.今天做了什么上午上工程实训课,老师先讲了许多铁道的知识,接着讲解了如何为高铁办理发车,和如何开高铁。然后我们就实际上手操作。这节课收获很多。下午上java课,写数据库,感觉很难好在最后写出来了,以后有时间写个教程。二.遇到的问题,如何解决无......
  • 数通HCIE_TCP
    TCP:传输控制协议0.TCP概述· TCP是一种面向连接的、可靠的传输层通信协议,由IETF的RFC793定义。 1.TCP报文格式 2.TCP的建立:三次握手 3.TCP的关闭:四次挥手 ......
  • Redis淘汰策略-231005
    Redis的内存淘汰策略有哪些:noeviction:当内存不足以容纳新写入数据时,新写入操作会报错;allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key。(这个是最常用的);allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key。设置过期时间的键空间......
  • 【2023年10月10日】STF61_docker_Day01(上午)
     STF61_docker_Day01(上午)1. 什么是docker?docker类似于VMware软件,也能虚拟出来很多的系统,虚拟出来的系统不叫虚拟机,叫容器。docker:linux系统上的虚拟机2. docker和传统虚拟机的区别VM:使用VMware提供虚拟机的运行平台,管理每个VM中操作系统的运行。每个VM都有自己......
  • 10.10算法
    爬楼梯假设你正在爬楼梯。需要n 阶你才能到达楼顶。每次你可以爬1或2个台阶。你有多少种不同的方法可以爬到楼顶呢? 示例1:输入:n=2输出:2解释:有两种方法可以爬到楼顶。1.1阶+1阶2.2阶示例2:输入:n=3输出:3解释:有三种方法可以爬到楼顶。1.1阶+1阶+1阶2.......
  • WIN10/11家庭版启用组策略
    平台:win10Home目的:启用组策略Windows10/11的组策略是一个非常重要且实用的功能,可以为计算机和用户指定相应操作的高级设置。比如企业管理员通过组策略设置,禁止同一域中的用户安装应用程序。个人计算机用户没有加入域,也可以设置组策略,一般指「本地组策略」。组策略的更改有计算......
  • TIOBE 发布 2023年10 月编程语言排行榜:Java 占比下跌 3.92%成第四
    转载TIOBE发布10月编程语言排行榜:Java占比下跌3.92%成第四(msn.cn)本月Python、C、Java均有所下跌,而Java的跌幅最大,为-3.92%,掉到第四,而C#的涨幅最大,增长了3.29%。对此,TIOBE的CEOPaulJansen认为,C#和Java之间的差距从未如此之小,Java受欢迎程度下降的主要......
  • 微软正式发布 C# 10,支持.NET 6 和 Visual Studio 2022 (附更新内容大全)
    微软正式发布C#10,支持.NET6和VisualStudio2022(附更新内容大全)2022/2/1211:24:36 来源:IT之家 作者:潇公子 责编:潇公子评论:0IT之家 2月12日消息,据微软中国MSDN,宣布C#10作为.NET6和VisualStudio2022的一部分已经发布了。在这篇文章中,微软将介绍C#......