TcpListener performance issues with Start() after hundreds of ports open

余生颓废 提交于 2019-12-08 00:27:31

问题


Before i get started... this is NOT FOR PRODUCTION; The question really only came about while making a test application. Myself and another developer were poking around with why .net was performing this poorly this way. It may not be .net at all, it could be the OS, I hope someone can shed some light on topic:

My test application was created to handle hundreds of connections from our production app which connects to hundreds of devices via TCP only because its easier to simulate 500-700 PCs then then have 500-700 physical machines stacked up in my office running some port software.

I created a sample chunk that you can copy/paste into your test VS if you are interested in finding a solution. Its quite simple and easy to reproduce.

Issues:

  • As each port is opened, it takes longer and longer for the next port to open.
  • The CPU is quite intense just to create one port after it has created several hundred

Notes:

  • Thread count is normal... very low (16ish threads in task manager)
  • Handle count is also normal as it adds each socket.
  • Memory usage also looks normal
  • Used reflector to look at the .net libs to see what Start() was doing, and it looks like normal socket calls.

Sample Code:

using System;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;

namespace SocketPerformanceTest
{
    class Program
    {
        static void Main(string[] args)
        {
            const int socketToOpen = 500;
            const int socketStartingPoint = 45000;
            var sw = new Stopwatch();
            for (var i = 0; i < socketToOpen; i++)
            {
                var thisPort = socketStartingPoint + i;
                try
                {
                    var listener = new TcpListener(IPAddress.Any, thisPort);
                    sw.Restart();
                    listener.Start();
                    sw.Stop();
                    Console.WriteLine("Started Port {0} in {1}", thisPort, sw.Elapsed);
                }
                catch{}
            }
        }
    }
}

Console Output:

When the test application first starts, notice that each port slowly rises in execution time. The Stopwatch wraps the Start() method:

Started Port 45000 in 00:00:00.0086440
Started Port 45001 in 00:00:00.0131427
Started Port 45002 in 00:00:00.0125916
Started Port 45003 in 00:00:00.0140987
Started Port 45004 in 00:00:00.0214274
Started Port 45005 in 00:00:00.0166746
Started Port 45006 in 00:00:00.0178583
Started Port 45007 in 00:00:00.0203611
Started Port 45008 in 00:00:00.0187707
Started Port 45009 in 00:00:00.0209386
Started Port 45010 in 00:00:00.0229595
Started Port 45011 in 00:00:00.0298687
Started Port 45012 in 00:00:00.0331132
Started Port 45013 in 00:00:00.0312815
Started Port 45014 in 00:00:00.0295004
Started Port 45015 in 00:00:00.0312391
Started Port 45016 in 00:00:00.0326538
Started Port 45017 in 00:00:00.0329316
Started Port 45018 in 00:00:00.0330471
Started Port 45019 in 00:00:00.0353324
Started Port 45020 in 00:00:00.0391780
Started Port 45021 in 00:00:00.0405106
Started Port 45022 in 00:00:00.0391909
Started Port 45023 in 00:00:00.0410726
Started Port 45024 in 00:00:00.0519416

After about 400 ports are opened, notice how long it takes for each port to start. 1-2 seconds? CPU is also quite high for this operation:

Started Port 45399 in 00:00:01.3031324
Started Port 45400 in 00:00:01.2686192
Started Port 45401 in 00:00:01.2367192
Started Port 45402 in 00:00:01.3912566
Started Port 45403 in 00:00:01.2710675
Started Port 45404 in 00:00:01.2500153
Started Port 45405 in 00:00:01.2685378
Started Port 45406 in 00:00:01.3358896
Started Port 45407 in 00:00:01.2972177
Started Port 45408 in 00:00:01.3002466
Started Port 45409 in 00:00:01.4087936
Started Port 45410 in 00:00:01.5042491
Started Port 45411 in 00:00:01.2869177
Started Port 45412 in 00:00:01.3284299
Started Port 45413 in 00:00:01.3202311
Started Port 45414 in 00:00:01.4406063
Started Port 45415 in 00:00:01.3534663
Started Port 45416 in 00:00:01.7562387
Started Port 45417 in 00:00:01.5572173
Started Port 45418 in 00:00:01.4617214
Started Port 45419 in 00:00:02.1260768
Started Port 45420 in 00:00:01.6841706
Started Port 45421 in 00:00:01.7514512
Started Port 45422 in 00:00:01.5182234

Questions:

  • Why does each port take longer to open then the last?
  • Why does the CPU get higher and higher
  • Am I doing something wrong? Is there a more efficient way to open a socket and listen for connections?
  • Is this an OS issue, or a .net issue? I tested this on windows 7, do you think it will be different if I tested it on a Server OS? I believe the kernel with 2008 R2 and Win7 SP'ed are the same, so not sure if that matters.

Hardware:

  • Win7 x64 Ultimate, 8 GB ram, I7, SSD, etc etc

It is not critical for me to find a solution for this, but it would be nice. I would like to have this simulator app start up, and listen to 500-700 unique TCP ports in a reasonable period of time. If there is a better way, please let me know... I am very interested on what is going on or alternative options.

Thanks!

Update 1

Tested it on a Raspberry Pi device which has hardly any CPU/Memory, and it was nearly instant. Others said it was instant in the comments.. and one said they saw the same thing. I also tested on a different PC, same issue I have. Disabled Firewall, AV, etc. I am really curious to why this is happening.

来源:https://stackoverflow.com/questions/14249739/tcplistener-performance-issues-with-start-after-hundreds-of-ports-open

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!