0

I have a file transfer application (server-client) ... while sending a file, i want to enable cancellation.
Client Cancel the SendFile method that it works by backgroundworker then it sends a command to the server to cancel its receiving thread.
when server receives this command it calls Stop method but it stucks in that line network.Read(data, 0, data.Length);

how can i abort this thread and go to finally without stucking in network.Read(..) ??
thanks in advance.

Thread thTransferFile = null;

void Start()
{
    thTransferFile = new Thread(unused => ft.Receive(destPath, Convert.ToInt64(fileSize);
    thTransferFile.Start();
}

void Stop()
{
    thTransferFile.Abort();
}


public void Receive(string destPath, long fileSize)
    {
        using (fs = new FileStream(destPath, FileMode.Create, FileAccess.Write))
        {
            try
            {
                int count = 0;
                long sum = 0;
                data = new byte[packetSize];
                while (sum < fileSize)
                {
                    count = network.Read(data, 0, data.Length);   //thread stucks in this line when i abort it
                    fs.Write(data, 0, count);
                    sum += count;
                }
            }
            finally
            {
                network.Write(new byte[1], 0, 1); //tell client that the file transfer ends
                network.Flush();
                fs.Dispose();
                if (Thread.CurrentThread.ThreadState == ThreadState.AbortRequested)
                {
                    File.Delete(destPath);
                }
            }
      }
Murhaf Sousli
  • 12,622
  • 20
  • 119
  • 185

3 Answers3

1

Instead of aborting the thread, Close() the network. It will throw the exception like you are expecting.

Killing threads is a big no-no, since there are resources that can be left uncleaned...

Daniel Mošmondor
  • 19,718
  • 12
  • 58
  • 99
1

NetworkStream.Read is blocked until it receives data. Set a timeout on the read operation by using NetworkStream's ReadTimeoutRead the community comment. Also, you may want to reconsider using Abort() to kill your thread. Add a boolean flag in your while loop, and set that flag to false when Stop() is called. This stop flag, combined with a ReadTimeout will ensure that your program eventually exits.

The thread that calls Abort might block if the thread that is being aborted is in a protected region of code, such as a catch block, finally block, or constrained execution region. If the thread that calls Abort holds a lock that the aborted thread requires, a deadlock can occur.

Tung
  • 5,334
  • 1
  • 34
  • 41
  • how much time should i set in ReadTimeout .. you know network sometime lag for some reason .. i can't make too short that might cancel the receiving without a cancel command .. and why should i stop using Thread.Abort .. i think its better than checking for flag each time i receive a packet .. plus i need that thread to execute "a protected region" like [finally] .. so FileStream disposes in any case (error,cancellation,success). – Murhaf Sousli Mar 10 '12 at 08:27
  • @Mur, I agree that ReadTimeout is suboptimal, as you can never be certain how long is long enough, but a high value is better than indefinite. Have you considered using BeginRead instead? As other members have pointed out, `Abort()` is generally not advisable. One can never be certain what the thread is doing when it's interrupted. Here's one [discussion](http://stackoverflow.com/questions/3923457/is-cs-using-statement-abort-safe). I also believe that your finally block is only going to be executed if the Abort() occurs within the try block. – Tung Mar 10 '12 at 10:03
  • @Tung - I hope that you don't build your code on the false assumption: This method reads data into the buffer parameter and returns the number of bytes successfully read. If no data is available for reading, the Read method returns 0. The Read operation reads as much data as is available, up to the number of bytes specified by the size parameter. If the remote host shuts down the connection, and all available data has been received, the Read method completes immediately and return zero bytes. (taked from http://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.read.aspx) – Daniel Mošmondor Mar 10 '12 at 13:37
  • What I wanted to say: Read() won't BLOCK. – Daniel Mošmondor Mar 10 '12 at 13:38
  • @Tung you might be right .. using beginRead would help it .. but when i used if(network.DataAvailable) it totally worked .. and aborting that thread never stuck again .. – Murhaf Sousli Mar 10 '12 at 18:01
  • @DanielMošmondor Read() .. does block ... and it doesn't return zero .. because networkStream is connected and i didn't set a timeout .. so it does wait for incoming data .. problem solved check out the answer – Murhaf Sousli Mar 10 '12 at 18:05
  • Hm, I have project that relies on the fact that it doesn't block. However, I have a stream that comes out from HttpResponse, maybe that is the difference. In any case, glad you solved your problem. – Daniel Mošmondor Mar 10 '12 at 19:17
0

i've found a solution when i cancel sending from client side .. the network.DataAvailable set to false .. so i added this line to my receive method in the server

in the while loop:

                while (sum < fileSize)
                {
                    if (network.DataAvailable)
                    {
                        count = network.Read(data, 0, data.Length);
                        fs.Write(data, 0, count);
                        sum += count;
                    }
                }

so it will never stuck at network.Read anymore. it totally worked

Murhaf Sousli
  • 12,622
  • 20
  • 119
  • 185
  • 1
    checking for data available is definitely a step in the right direction, but the overall solution is too reminiscent of a spinlock. How often is your data not available when your code runs? – Tung Mar 10 '12 at 09:42
  • @Tung i've not explain about my code in that question because all i wanted is aborting thread thing .. but the way i built my application .. network.DataAvailable is always true .. until a cancellation made or network closes .. only in these two cases. – Murhaf Sousli Mar 10 '12 at 18:29