简体   繁体   中英

Shared folder too many connections problem in c#

I'm trying to copy several files to a shared folder (Aprox 20), but each file simultaneously on different threads.

I'm using a Code like this to copy the file

AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);    
WindowsIdentity identity = new WindowsIdentity(username, password);
WindowsImpersonationContext context = identity.Impersonate();

try
{
    File.Copy(@"c:\temp\MyFile.txt", @"\\server\folder\Myfile.txt", true);
}
catch
{
    context.Undo();
}

but some of the files don't get copied and the error that I get is the following:

"No se pueden realizar más conexiones a este equipo remoto en este momento, ya que hay más de las que puede aceptar"

Translated would be something like

"No more connections can be made to this remote computer at this time, as there are more connections that it can accept"

Is there another way to copy the file to the shared folder or to explicity close the connection?

Windows workstations have a limit on the number of network connections they can accept concurrently.

You could:

  • Use fewer than 20 connections
  • Use a different file copy protocol, although you'll then run into the limit on the number of network sockets
  • Switch to using a server OS, where there is no such limit

Try copying the files over the same thread. I'm sure having one thread per connection is allowing the server to hit its limit.

Windows client operating systems are limited to the number of concurrent connections they can accept. Even if this is a server system, Windows file sharing also allows the administrator to limit the number of connections to the share.

What you probably want to do is limit yourself to just a few simultaneous threads (3 to 5 ought to do it). Put all the filenames into a queue and have each thread dequeue (with appropriate locking) the next file to process until the queue is empty. This is called a producer/consumer scheme. As a bonus, you'll likely end up with more throughput than doing all 20 at once anyway, because the system has to spend less time worrying about network collisions and context switches.

Well remember that IO speeds are almost always a bottleneck so you may be better off limiting the transfer to 1 or 2 files at a time. You are probably pegging either the disk reads or network throughput. Your best bet is to measure performance starting from 1 Thread and seek a balance of transfer speed and Threads.

The issue is that each thread is making its own connection. If you have more threads running thatn te target machine can accept, you will run into this problem. You need to find a way to ensure that you don't exceed this limit.

Is there a reason this needs to be multi-threaded? I'm sure the answer is "yes", but just in case you're thinking that multi-threading is going to speed up the copy operations by allowing multiple copy operations to happen at once, this is not the case. There is only so much bamdwidth, and the target PC will only be able to read/write at a specific speed, so by trying to write multiple files at multiple threads, you'd actually just be slowing down each file individually.

If I'm guessing right, however, and there is another reason for multiple threads, then let me offer an alternative: Write the files locally and have a completely different process copy files over. Have a Windows Service or a Console application that can copy the files, while your UI thread and other threads go about their work. Adding a middle-man may add a bit of extra complexisty, but it's still simpler than trying to find a way to make this problem go away.

The alternative would be to have to keep track of threads, and ensure that the number of threads never exceeds the number of connections available onteh target machine, AND you have to worry about other processes connecting to the machine, so you can't really count on this approach, either.

Keeping track of the threads, and locking properly is certainly doable, but simply writing the files locally and having an external program do the file transfer is by far easier to write, and simpler to troubleshoot.

Another option could be to use a Network drive - check for the existence, and map if necessary. Code for mapping and un-mapping the drive can be found in my answer here:

Once the drive is mapped, your code should use the same connection regardless of the thread. We use this in a web service call, which is, by its very nature, multi-threaded, and it's a highly used service, copying hundreds of files per minute at peak times. I'm relatively sure it will work in your case.

C# - Map Network drive from Web Service

To check to see if the drive is already mapped, simply call

if (System.IO.Directory.Exists(<drive letter here>));

Edit - adding code to connect and disconnect network drives

public static class NetworkDrives
    {
        public static bool  MapDrive(string DriveLetter, string Path, string Username, string Password)
        {

            bool ReturnValue = false;

            if(System.IO.Directory.Exists(DriveLetter + ":\\"))
            {
                DisconnectDrive(DriveLetter);
            }
            System.Diagnostics.Process p = new System.Diagnostics.Process();
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.CreateNoWindow = true;
            p.StartInfo.RedirectStandardError = true;
            p.StartInfo.RedirectStandardOutput = true;

            p.StartInfo.FileName = "net.exe";
            p.StartInfo.Arguments = " use " + DriveLetter + ": " + Path + " " + Password + " /user:" + Username;
            p.Start();
            p.WaitForExit();

            string ErrorMessage = p.StandardError.ReadToEnd();
            string OuputMessage = p.StandardOutput.ReadToEnd();
            if (ErrorMessage.Length > 0)
            {
                throw new Exception("Error:" + ErrorMessage);
            }
            else
            {
                ReturnValue = true;
            }
            return ReturnValue;
        }
        public static bool DisconnectDrive(string DriveLetter)
        {
            bool ReturnValue = false;
            System.Diagnostics.Process p = new System.Diagnostics.Process();
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.CreateNoWindow = true;
            p.StartInfo.RedirectStandardError = true;
            p.StartInfo.RedirectStandardOutput = true;

            p.StartInfo.FileName = "net.exe";
            p.StartInfo.Arguments = " use " + DriveLetter + ": /DELETE";
            p.Start();
            p.WaitForExit();

            string ErrorMessage = p.StandardError.ReadToEnd();
            string OuputMessage = p.StandardOutput.ReadToEnd();
            if (ErrorMessage.Length > 0)
            {
                throw new Exception("Error:" + ErrorMessage);
            }
            else
            {
                ReturnValue = true;
            }
            return ReturnValue;
        }

    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM