1

私がすべてを正しく行っていることを確認し、他の誰かを助けることを期待して、ファイルをアップロードするためのテストアプリを作成し、ここに投稿して私の問題の助けを求めることにしました。それが私を助けながら他の誰かを助けることを願っています!;)

注目に値する: -私はこれを遅い接続でテストしており、これをテストするためだけにftpユーザーアカウントの速度を約10kb/sに制限しています。

問題: 新しく作成したスレッド(関数UploadAFile-> UF_Thread)を使用してファイルをアップロードする場合、以下のスニップでパケットを送信します。requestStream.Write()が返され、スレッドが続行できるようになっている場合でも、サーバーにパケットが表示されます。まだ送信中です。100個のパケットが送信されるまでに3秒が経過し、サーバー上ですべてのパケットを送信するループでファイルをアップロードするのに約26秒かかります(この間、アプリはただ座って、進行状況が表示されなくなるのを待ちます23秒前にGUIに従って終了したためです)。

期待される結果: パケットが終了するまでbStillSendingをtrueに設定する方法を見つける必要があります。各パケットを待ちたい。

snip-itを開始します

DateTime startTimestamp = DateTime.Now;
requestStream.Write(buffer, 0, bytesRead);

//Wait for packet to get to server
bool bStillSending = false;
do
{
  Thread.Sleep(50);
} while (bStillSending);

bytesRead = sourceStream.Read(buffer, 0, ufParams.PacketSize);
lBytesSent += bytesRead;

TimeSpan tsUploadTime = DateTime.Now.Subtract(startTimestamp);
if (tsUploadTime.Milliseconds > 0) lstSpeedInBytesPerMillisecond.Add(bytesRead / tsUploadTime.Milliseconds);
else lstSpeedInBytesPerMillisecond.Add(bytesRead);
sSpeed = ConvertBytesToLargestType(lstSpeedInBytesPerMillisecond.Last());
Raise_UploadFile_Progress_Event(bytesRead, lBytesSent, sourceStream.Length, sSpeed);

snip-itを終了します

アプリケーション全体の開始

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Net;
using System.Threading;
using System.Windows;

namespace WindowsFormsApplication1
{
    class UploadFile
    {
        #region Private class variables
        private ManualResetEvent m_MRE_StopUpload = new ManualResetEvent(false);
        #endregion

        #region Private class structures
        private class UploadFile_PARAMS
        {
            #region Local private class variables
            private int m_iThreadID = 0;
            private ManualResetEvent m_MRE_StopUpload = new ManualResetEvent(false);
            private string m_sServer = "";
            private string m_sUser = "";
            private string m_sPass = "";
            private string m_sSourcePath = "";
            private string m_sDestPath = "";
            private int m_iPacketSize = 512;
            #endregion

            #region Properties
            public int ThreadID
            {
                get
                {
                    return m_iThreadID;
                }
                set
                {
                    m_iThreadID = value;
                }
            }

            public ManualResetEvent MRE_StopUpload
            {
                get
                {
                    return m_MRE_StopUpload;
                }
                set
                {
                    m_MRE_StopUpload = value;
                }
            }

            public string Server
            {
                get
                {
                    return m_sServer;
                }
                set
                {
                    m_sServer = value;
                }
            }

            public string User
            {
                get
                {
                    return m_sUser;
                }
                set
                {
                    m_sUser = value;
                }
            }

            public string Pass
            {
                get
                {
                    return m_sPass;
                }
                set
                {
                    m_sPass = value;
                }
            }

            public string SourcePath
            {
                get
                {
                    return m_sSourcePath;
                }
                set
                {
                    m_sSourcePath = value;
                }
            }

            public string DestPath
            {
                get
                {
                    return m_sDestPath;
                }
                set
                {
                    m_sDestPath = value;
                }
            }

            public int PacketSize
            {
                get
                {
                    return m_iPacketSize;
                }
                set
                {
                    m_iPacketSize = value;
                }
            }
            #endregion
        }
        #endregion

        #region Public class methods
        //Public method UploadFile
        public void UploadSingleFile(string sServer, string sUser, string sPass, string sSourcePath, string sDestPath, int iPacketSize)
        {
            UploadFile_PARAMS ufParams = new UploadFile_PARAMS();
            ufParams.Server = sServer;
            ufParams.User = sUser;
            ufParams.Pass = sPass;
            ufParams.SourcePath = sSourcePath;
            ufParams.DestPath = sDestPath;
            ufParams.PacketSize = iPacketSize;
            ufParams.MRE_StopUpload = m_MRE_StopUpload;

            UploadAFile(ufParams);
        }

        //Public method CancelUpload
        public void CancelUpload()
        {
            m_MRE_StopUpload.Set();
        }
        #endregion

        #region Public class events
        //Public event UploadFile_Progress
        public delegate void UploadFile_Progress_EventHandler(long lBytesSent, long lTotalBytesSent, long lTotalFileSizeBytes, string sSpeed);
        public event UploadFile_Progress_EventHandler UploadFile_Progress;
        private void Raise_UploadFile_Progress_Event(long lBytesSent, long lTotalBytesSent, long lTotalFileSizeBytes, string sSpeed)
        {
            if (this.UploadFile_Progress != null)
            {
                //The event handler exists so raise the event to it
                this.UploadFile_Progress(lBytesSent, lTotalBytesSent, lTotalFileSizeBytes, sSpeed);
            }
        }

        //Public event UploadFile_Complete
        public delegate void UploadFile_Complete_EventHandler(long lTotalBytesSent, long lTotalFileSizeBytes, bool bError, string sAverageSpeed, TimeSpan tsTimeItTookToUpload);
        public event UploadFile_Complete_EventHandler UploadFile_Complete;
        private void Raise_UploadFile_Complete_Event(long lTotalBytesSent, long lTotalFileSizeBytes, bool bError, string sAverageSpeed, TimeSpan tsTimeItTookToUpload)
        {
            if (this.UploadFile_Complete != null)
            {
                //The event handler exists so raise the event to it
                this.UploadFile_Complete(lTotalBytesSent, lTotalFileSizeBytes, bError, sAverageSpeed, tsTimeItTookToUpload);
            }
        }

        //Public event UploadFile_Error
        public delegate void UploadFile_Error_EventHandler(string sErrorMessage);
        public event UploadFile_Error_EventHandler UploadFile_Error;
        private void Raise_UploadFile_Error_Event(string sErrorMessage)
        {
            if (this.UploadFile_Error != null)
            {
                //The event handler exists so raise the event to it
                this.UploadFile_Error(sErrorMessage);
            }
        }
        #endregion

        #region Private class functions
        //Private class function ConvertBytesToLargestType
        private string ConvertBytesToLargestType(long lBytesAMillisecond)
        {
            //Convert the byte count to the highest type
            double dKiloBytesAMillisecond = (double)lBytesAMillisecond / (double)1024;
            double dMegaBytesAMillisecond = dKiloBytesAMillisecond / (double)1024;
            double dGigaBytesAMillisecond = dMegaBytesAMillisecond / (double)1024;

            if (dGigaBytesAMillisecond >= 1)
            {
                return dGigaBytesAMillisecond.ToString("#.##") + "Gb/s";
            }

            if (dMegaBytesAMillisecond >= 1)
            {
                return dMegaBytesAMillisecond.ToString("#.##") + "Mb/s";
            }

            if (dKiloBytesAMillisecond >= 1)
            {
                return dKiloBytesAMillisecond.ToString("#") + "kb/s";
            }

            return lBytesAMillisecond.ToString("#") + "b/s";
        }
        #endregion

        #region Private class multi-threading functions
        //Thread creation for UploadAFile
        System.Threading.Thread threadUF;
        private void UploadAFile(UploadFile_PARAMS ufParams)
        {
            //Make sure to destory any old objects
            if (threadUF != null)
            {
                if (threadUF.IsAlive) threadUF.Abort();
                while (threadUF.IsAlive) Application.DoEvents();
                threadUF = null;
                GC.Collect();
            }

            //Make sure the params object is not null
            if (ufParams == null) return;

            //Create the new thread
            threadUF = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(UF_Thread));
            threadUF.IsBackground = true;
            ufParams.ThreadID = threadUF.ManagedThreadId;

            //Start the thread
            threadUF.Start(ufParams);
        }
        private void UF_Thread(Object oParameter)
        {
            //Extract (cast) the params
            UploadFile_PARAMS ufParams = (UploadFile_PARAMS)oParameter;

            FtpWebRequest request;
            FtpWebResponse response;

            Stream sourceStream = new MemoryStream();
            Stream requestStream = sourceStream;

            long lBytesSent = 0;
            string sSpeed = "";
            TimeSpan tsTimeToUploadFile;
            DateTime dtStartedUpload = DateTime.Now;
            List<long> lstSpeedInBytesPerMillisecond = new List<long>();

            try
            {
                request = (FtpWebRequest)WebRequest.Create("ftp://" + ufParams.Server + ufParams.DestPath);
                request.Method = WebRequestMethods.Ftp.UploadFile;
                request.Credentials = new NetworkCredential(ufParams.User, ufParams.Pass);

                sourceStream = new FileStream(ufParams.SourcePath, FileMode.Open);

                requestStream = request.GetRequestStream();
                request.ContentLength = sourceStream.Length;

                byte[] buffer = new byte[ufParams.PacketSize];
                int bytesRead = sourceStream.Read(buffer, 0, ufParams.PacketSize);

                do
                {
                    DateTime startTimestamp = DateTime.Now;
                    requestStream.Write(buffer, 0, bytesRead);

                    //Wait for packet to get to server
                    bool bStillSending = false;
                    do
                    {
                      Thread.Sleep(50);
                    } while (bStillSending);

                    bytesRead = sourceStream.Read(buffer, 0, ufParams.PacketSize);
                    lBytesSent += bytesRead;

                    TimeSpan tsUploadTime = DateTime.Now.Subtract(startTimestamp);
                    if (tsUploadTime.Milliseconds > 0) lstSpeedInBytesPerMillisecond.Add(bytesRead / tsUploadTime.Milliseconds);
                    else lstSpeedInBytesPerMillisecond.Add(bytesRead);
                    sSpeed = ConvertBytesToLargestType(lstSpeedInBytesPerMillisecond.Last());
                    Raise_UploadFile_Progress_Event(bytesRead, lBytesSent, sourceStream.Length, sSpeed);
                } while (bytesRead > 0 && ufParams.MRE_StopUpload.WaitOne(0) == false);

                if (ufParams.MRE_StopUpload.WaitOne(0)) throw new System.Net.WebException("Upload was canceled!");

                //Close the stream to show we are finished with the file
                requestStream.Close();

                response = (FtpWebResponse)request.GetResponse();
                if (lstSpeedInBytesPerMillisecond.Count > 0)
                {
                    sSpeed = ConvertBytesToLargestType(Convert.ToInt64(lstSpeedInBytesPerMillisecond.Average()));
                }
                else sSpeed = "0 b/s";
                tsTimeToUploadFile = DateTime.Now.Subtract(dtStartedUpload);
                Raise_UploadFile_Complete_Event(lBytesSent, sourceStream.Length, false, sSpeed, tsTimeToUploadFile);
            }
            catch (Exception ex)
            {
                Raise_UploadFile_Error_Event(ex.GetType().Name + ": " + ex.Message);
                if (lstSpeedInBytesPerMillisecond.Count > 0)
                {
                    sSpeed = ConvertBytesToLargestType(Convert.ToInt64(lstSpeedInBytesPerMillisecond.Average()));
                }
                else sSpeed = "0 b/s";
                tsTimeToUploadFile = DateTime.Now.Subtract(dtStartedUpload);
                Raise_UploadFile_Complete_Event(lBytesSent, sourceStream.Length, true, sSpeed, tsTimeToUploadFile);
            }
            finally
            {
                request = null;

                sourceStream.Close();
                sourceStream = null;

                requestStream.Close();
                requestStream = null;
            }
        }
        #endregion
    }

    public partial class Form1 : Form
    {
        //Define the upload object as a global form object
        UploadFile upload;

        public Form1()
        {
            InitializeComponent();
        }

        #region Buttons
        private void button1_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog1 = new OpenFileDialog();

            openFileDialog1.InitialDirectory = "c:\\";
            openFileDialog1.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
            openFileDialog1.FilterIndex = 2;
            openFileDialog1.RestoreDirectory = true;

            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                if (File.Exists(openFileDialog1.FileName))
                {
                    label1.Text = openFileDialog1.FileName;
                    listView1.Items.Add("Selected file to upload.");
                }
                else
                {
                    label1.Text = "";
                    listView1.Items.Add("File choosen does not exist!");
                }
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            if (!File.Exists(label1.Text))
            {
                listView1.Items.Add(DateTime.Now.ToString("hh:mm:ss:f") + " Error!  File selected does not exist!");
                return;
            }

            listView1.Items.Add(DateTime.Now.ToString("hh:mm:ss:f") + " Starting the upload process...");

            progressBar1.Minimum = 0;
            progressBar1.Maximum = 100;

            upload = new UploadFile();
            upload.UploadFile_Progress += new UploadFile.UploadFile_Progress_EventHandler(upload_UploadFile_Progress);
            upload.UploadFile_Complete += new UploadFile.UploadFile_Complete_EventHandler(upload_UploadFile_Complete);
            upload.UploadFile_Error += new UploadFile.UploadFile_Error_EventHandler(upload_UploadFile_Error);
            upload.UploadSingleFile("ftp.xentar.com", "arvo", "S1mP13", label1.Text, "/arvo/" + Path.GetFileName(label1.Text), 1024);
        }

        private void button3_Click(object sender, EventArgs e)
        {
            listView1.Items.Add(DateTime.Now.ToString("hh:mm:ss:f") + " Canceling upload...");
            upload.CancelUpload();
        }
        #endregion

        #region UploadFile object events
        private void upload_UploadFile_Error(string sErrorMessage)
        {
            listView1.Items.Add(DateTime.Now.ToString("hh:mm:ss:f") + " Error!  " + sErrorMessage);
        }

        private void upload_UploadFile_Complete(long lTotalBytesSent, long lTotalFileSizeBytes, bool bError, string sAverageSpeed, TimeSpan tsTimeItTookToUpload)
        {
            if (bError)
            {
                AddItemToLog("Error uploading file!");
            }
            else
            {
                AddItemToLog("Upload complete!");
                AddItemToLog("It took " + tsTimeItTookToUpload.ToString("mm") + " minutes and " + tsTimeItTookToUpload.ToString("ss") + " seconds to upload the file.");
                UpdateProgressBar(100, lTotalBytesSent);
            }
        }

        private void upload_UploadFile_Progress(long lBytesSent, long lTotalBytesSent, long lTotalFileSizeBytes, string sSpeed)
        {
            int iProgressComplete = Convert.ToInt32(((double)lTotalBytesSent / (double)lTotalFileSizeBytes) * 100);
            UpdateProgressBar(iProgressComplete, lTotalBytesSent);
        }
        #endregion

        #region Thread-safe functions
        private void AddItemToLog(string sLogEntry)
        {
            //Send to tread safe call
            ThreadSafe_AddItemToLog(sLogEntry);
        }
        delegate void ThreadSafe_AddItemToLog_Callback(string sLogEntry);
        private void ThreadSafe_AddItemToLog(string sLogEntry)
        {
            if (this.InvokeRequired)
            {
                ThreadSafe_AddItemToLog_Callback d =
                    new ThreadSafe_AddItemToLog_Callback(ThreadSafe_AddItemToLog);
                try
                {
                    this.Invoke(d, new object[] { sLogEntry });
                }
                catch
                {
                    //ObjectDisposedException
                }
            }
            else
            {
                //Send the call on to the normal function
                ThreadSafe_AddItemToLog_Proc(sLogEntry);
            }
        }
        private void ThreadSafe_AddItemToLog_Proc(string sLogEntry)
        {
            listView1.Items.Add(DateTime.Now.ToString("hh:mm:ss:f") + " " + sLogEntry);
        }

        private void UpdateProgressBar(int iProgressBarValue, long lTotalBytesSent)
        {
            //Send to tread safe call
            ThreadSafe_UpdateProgressBar(iProgressBarValue, lTotalBytesSent);
        }
        delegate void ThreadSafe_UpdateProgressBar_Callback(int iProgressBarValue, long lTotalBytesSent);
        private void ThreadSafe_UpdateProgressBar(int iProgressBarValue, long lTotalBytesSent)
        {
            if (this.InvokeRequired)
            {
                ThreadSafe_UpdateProgressBar_Callback d =
                    new ThreadSafe_UpdateProgressBar_Callback(ThreadSafe_UpdateProgressBar);
                try
                {
                    this.Invoke(d, new object[] { iProgressBarValue, lTotalBytesSent });
                }
                catch
                {
                    //ObjectDisposedException
                }
            }
            else
            {
                //Send the call on to the normal function
                ThreadSafe_UpdateProgressBar_Proc(iProgressBarValue, lTotalBytesSent);
            }
        }
        private void ThreadSafe_UpdateProgressBar_Proc(int iProgressBarValue, long lTotalBytesSent)
        {
            label4.Text = lTotalBytesSent.ToString();
            progressBar1.Value = iProgressBarValue;
        }
        #endregion
    }
}
4

2 に答える 2

1

そのように人為的に速度を設定しても、低速リンクと同じ効果はありません。クライアントを制限すると、バッファから読み取る量が制限されますが、バッファが両端でいっぱいになるまで、送信される速度は実際には変更されません。

はるかに大きなファイルをアップロードしようとすると、バッファがいっぱいになるとアップロードストールが表示され、期待される速度で続行されます。

.Write()ソケットに書き込まれるまでブロックされます。非同期にする場合は、非同期.BeginWrite()呼び出しを使用する必要があります。

于 2012-07-22T09:07:41.320 に答える
0

バックグラウンドワーカーを使用してプログレスバーを処理してみませんか。待機させたい場合は、メインスレッドを停止させません。

于 2012-07-16T11:59:45.417 に答える