コード例 #1
0
                public bool Send(String _filePath, String _baseFolder, String _targetFolder, String _streamName, int mbPerSec = 1000, bool block = false)
                {
                    this.filePath       = _filePath;
                    this.baseFolder     = _baseFolder;
                    this.targetFolder   = _targetFolder;
                    this.streamName     = _streamName;
                    this.connectionLost = false;
                    bool     retVal      = true;
                    bool     transferOk  = true;
                    bool     writeFailed = false;
                    FileInfo thisFileinfo;
                    int      lastRead = 0;

                    bytesWritten      = 0;
                    totalBytesWritten = 0;
                    complete          = false;
                    errMsg            = "";

                    if (File.Exists(filePath))
                    {
                        thisFileinfo = new FileInfo(filePath);
                        lastWritten  = thisFileinfo.LastWriteTime;
                        length       = thisFileinfo.Length;
                    }
                    else
                    {
                        errMsg  = "Transfer failed: The Source file does not exist.";
                        retVal  = false;
                        running = false;
                        return(false);
                    }

                    createNewFailed   = false;
                    creatNewSucceeded = false;

                    if (running)
                    {
                        errMsg = "Transfer failed: A file is already being sent by this Transfer object.";
                        return(false);
                    }

                    running = true;

                    new Thread(() =>
                    {
                        // Convert this to long form:
                        mbPerSec = (mbPerSec * 1000000);

                        // Convert it to bytes.
                        mbPerSec = (mbPerSec / 8);

                        // We don't want to send more then mbPerSec bytes a second, so
                        // If buffersize if larger then it may happen. Let's make sure it
                        // doesn't.
                        if (bufferSize > mbPerSec)
                        {
                            bufferSize = mbPerSec;
                        }

                        try
                        {   // Create the reader filestream:
                            fs = new FileStream(filePath, FileMode.Open);
                        }
                        catch (Exception ex)
                        {
                            errMsg  = "file aborted: Could not access the source file: " + Path.GetFileName(filePath) + ". The error returned is: " + ex.Message;
                            retVal  = false;
                            running = false;
                            return;
                        }

                        // Define the cleanup function (it will be called from several different places).
                        Action <String> cleanUp = (String msg) =>
                        {
                            if (closeDatastream)
                            {
                                CloseDatastream(streamName);
                            }

                            try
                            {
                                // We're finished with the source file, so close it.
                                fs.Close();
                            }
                            catch (Exception) { }

                            callback(msg);
                            running = false;
                        };

                        // Make sure we haven't been stopped before we even begin:
                        if (!client.Running())
                        {
                            running = false;
                            cleanUp("file aborted - FileTransfer not running! (" + Path.GetFileName(filePath) + ")");
                            return;
                        }

                        // Define our DataStream name:
                        if (streamName.Equals(""))
                        {
                            streamName = filePath.Replace(@"\", "-"); closeDatastream = true;
                        }

                        Func <String, bool, bool> GetDataStream = (String thisStreamName, bool killExisting) =>
                        {
                            // Are we creating a new datastream for every transfer (slower), or reusing one over and over (faster)
                            if (closeDatastream || killExisting)
                            {
                                CloseDatastream(thisStreamName);
                            }

                            // Get the tcp DataStream
                            if (!client.GetDataStream(thisStreamName, ref thisDataStream, ref errMsg))
                            {
                                if (!client.CreateDataStream(thisStreamName, ref errMsg))
                                {
                                    errMsg = "file aborted (connection lost)! ( Could not create DataStream '" + streamName + "' )";
                                    CloseDatastream(thisStreamName);
                                    retVal  = false;
                                    running = false;
                                    return(false);;
                                }

                                if (!client.GetDataStream(thisStreamName, ref thisDataStream, ref errMsg))
                                {
                                    errMsg = "file aborted (connection lost)! ( Could not get DataStream '" + streamName + "' )";
                                    CloseDatastream(thisStreamName);
                                    retVal  = false;
                                    running = false;
                                    return(false);
                                }
                            }

                            return(true);
                        };

                        if (!GetDataStream(streamName, false))
                        {
                            retVal = false;
                            cleanUp(errMsg);
                            return;
                        }

                        // Re-define the DataStream's callback here so we can get control messages from it:
                        thisDataStream.callback = delegate(string msg, byte[] dataStreamBuffer, int numBytesContained, string sessionId)
                        {
                            if (dataStreamBuffer != null)
                            {
                                String thisMsg = TcpComm.Utilities.BytesToString(dataStreamBuffer, numBytesContained);

                                if (thisMsg == "complete:ok")
                                {
                                    complete = true;
                                }

                                if (thisMsg == "complete:failed")
                                {
                                    transferOk = false;
                                    complete   = true;
                                }

                                if (thisMsg == "new:ok")
                                {
                                    creatNewSucceeded = true;
                                }

                                if (thisMsg.StartsWith("new:failed:"))
                                {
                                    errMsg          = thisMsg.Replace("new:failed:", "Transfer Failed: ");
                                    createNewFailed = true;
                                }

                                if (thisMsg.StartsWith("writefailed:"))
                                {
                                    writeFailed = true;
                                }

                                if (thisMsg.StartsWith("written:"))
                                {
                                    thisMsg = thisMsg.Replace("written:", "");

                                    try
                                    {
                                        bytesWritten = int.Parse(thisMsg);
                                    }
                                    catch (Exception)
                                    {
                                        retVal = false;
                                        cleanUp("Transfer Failed: Could not read (parse) the number of bytes written by the server. Communication error.");
                                        return;
                                    }
                                }
                            }
                        };

                        // Define a control message of our own here:
                        String newCommand = "<command=new><path>" + filePath.Replace(baseFolder, "") + @"</path>";
                        if (File.Exists(filePath))
                        {
                            newCommand += "<length>" + length.ToString() + @"</length><date>" + lastWritten.ToString() + @"</date><targetfolder>" + targetFolder + "</targetfolder>";
                        }
                        else
                        {
                            retVal = false;
                            cleanUp("Transfer failed: The source file does not exist.");
                            return;
                        }

                        // Send our "new file transfer" control message to the file transfer server here:
                        if (!client.SendText(newCommand, streamName, ref errMsg))
                        {
                            errMsg = "file aborted (connection lost)! Could not communicate with server: " + errMsg;

                            try
                            {
                                fs.Close();
                            }
                            catch (Exception) { }

                            retVal = false;
                            cleanUp(errMsg);
                            return;
                        }

                        // Wait for the server's response for up to 3 second:
                        new Tools.WaitTimeout(3000, () => { return(createNewFailed || creatNewSucceeded); }).Wait();

                        // Did the server have a problem with our proposed transfer (or did it fail to respond within 3 seconds)?
                        if (createNewFailed)
                        {
                            try
                            {
                                fs.Close();
                            }
                            catch (Exception) { }

                            retVal = false;
                            cleanUp(errMsg);

                            return;
                        }

                        // The transfer has been accepted - on to the good stuff:
                        try
                        {   // Get the first chunk of file bytes that will be sent:
                            read     = fs.Read(buffer, 0, bufferSize);
                            lastRead = read;
                        }
                        catch (Exception ex)
                        {
                            errMsg = "Transfer failed: Can not read from source file: " + ex.Message;
                            retVal = false;
                            cleanUp(errMsg);
                            return;
                        }

                        if (mbPerSec > 0 && bufferSize > (mbPerSec / 4))
                        {
                            bufferSize = mbPerSec / 4;
                        }

                        DateTime timeout = DateTime.Now.AddSeconds(1);
                        int sentThisSec  = 0;

                        // Begin sending file bytes:
                        while (read > 0 && running && client.Running())
                        {
                            // Respect the throttle value here:
                            if (mbPerSec > 0)
                            {
                                if (sentThisSec >= mbPerSec && DateTime.Now < timeout)
                                {
                                    while (DateTime.Now < timeout)
                                    {
                                        Thread.Sleep(1);
                                    }
                                }

                                if (DateTime.Now >= timeout)
                                {
                                    timeout = DateTime.Now.AddSeconds(1); sentThisSec = 0;
                                }
                            }

                            // Actually send the bytes we've read here:
                            bytesWritten = 0;
                            if (!client.SendArray(buffer, read, streamName, ref errMsg))
                            {
                                errMsg = "file aborted (connection lost)! Can not communicate with file transfer server: " + errMsg;
                                retVal = false;
                                cleanUp(errMsg);
                                return;
                            }

                            sentThisSec       += read;
                            totalBytesWritten += read;

                            try
                            {   // Get some more bytes:
                                read = fs.Read(buffer, 0, bufferSize);
                            }
                            catch (Exception ex)
                            {
                                errMsg = "file aborted (connection lost)! Can not read from source file: " + ex.Message;
                                retVal = false;
                                cleanUp(errMsg);
                                return;
                            }

                            // Wait for the server to acknolage the last chunk of bytes read and sent:
                            packetTimeout = DateTime.Now.AddSeconds(15);
                            while (bytesWritten != lastRead && running && client.Running())
                            {
                                Thread.Sleep(1);
                                if (DateTime.Now > packetTimeout)
                                {
                                    // We've lost connection for some reason. Bail:
                                    connectionLost = true;
                                    break;
                                }

                                if (writeFailed)
                                {
                                    connectionLost = true; break;
                                }
                            }

                            if (connectionLost)
                            {
                                break;
                            }

                            lastRead = read;
                        }

                        try
                        {
                            // We're finished with the source file, so close it.
                            fs.Close();
                        }
                        catch (Exception) { }

                        if (writeFailed)
                        {
                            errMsg = "file aborted (connection lost)! A transfer operation with this ID could not be found in the server. ";
                            retVal = false;
                            cleanUp(errMsg);
                            return;
                        }

                        if (totalBytesWritten < length && !client.Running())
                        {
                            errMsg = "file aborted (connection lost)! Can not communicate with file transfer server: " + errMsg;
                            retVal = false;
                            cleanUp(errMsg);
                            return;
                        }

                        // Finishing up: has the client disconnected?
                        if (!client.Running())
                        {
                            running = false;
                        }

                        // Did we loose connection?
                        if (connectionLost)
                        {
                            // Attempt to send this no matter what:
                            CloseDatastream(streamName);

                            errMsg = "file aborted: connection lost during transfer! (" + Path.GetFileName(filePath) + ")";
                            retVal = false;
                            cleanUp(errMsg);
                            return;
                        }

                        // Are we being asked to shut down?
                        if (!running)
                        {
                            if (!client.SendArray(TcpComm.Utilities.StringToBytes("<command=abort>"), streamName, ref errMsg))
                            {
                                //running = false;
                            }

                            CloseDatastream(streamName);

                            errMsg = "file aborted! (" + Path.GetFileName(filePath) + ")";
                            retVal = false;
                            cleanUp(errMsg);
                            return;
                        }

                        if (!client.SendArray(TcpComm.Utilities.StringToBytes("<command=complete>" + length.ToString()), streamName, ref errMsg))
                        {
                            errMsg = "file aborted! (Could not send file complete message)";
                            retVal = false;
                            cleanUp(errMsg);
                            return;
                        }

                        // Wait for the server to acknolage that we're finished sending bytes for this file:
                        new WaitTimeout(14000, () => { return(complete || !running); }).Wait();

                        if (!complete)
                        {
                            errMsg = "file aborted (connection lost)! (" + Path.GetFileName(filePath) + ")";
                            CloseDatastream(streamName);
                            retVal = false;
                            cleanUp(errMsg);
                            return;
                        }

                        if (!transferOk)
                        {
                            errMsg = "file aborted (target corrupt)! (" + Path.GetFileName(filePath) + ")";
                            CloseDatastream(streamName);
                            retVal = false;
                            cleanUp(errMsg);
                            return;
                        }

                        // Clean up and exit.
                        retVal = true;
                        cleanUp("file Complete: " + Path.GetFileName(filePath));
                    }).Start();

                    if (block)
                    {
                        while (running)
                        {
                            Thread.Sleep(1);
                        }
                    }

                    return(retVal);
                }