使用Wininet API上傳文件到Web Server

使用Wininet API上傳文件到Web Server。它分爲客戶端和服務端兩塊,客戶端負責連接服務器,發送數據給服務端;服務端負責接收數據,保存。

首先看客戶端:
    在這裏,需要稍微解釋下URL的組成。舉個例子:http://myWebServer:8080/Handler/FileUploader.aspx
    其中 "myWebServer"爲Server Host Name,它用來表示服務器的IP地址。
    “8080”是該服務器對http開發的端口號,如不指定的話,默認爲80
    “/Handler/FileUploader.aspx”就是這個URL的UrlPath了

    使用Wininet API同服務器打交道,知道這麼多久可以了,下面看怎麼編寫客戶端代碼。其實它的步驟是很死的,只要按固定套路使用就可以了。
    1. 用 InternetOpen 創建一個表示該次連接的Internet句柄
        HINTERNET hInternet = ::InternetOpen(_T("Sample String"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
    2. 用 InternetConnect 與指定服務器連接,獲得本次連接句柄
        // hInternet就是InternetOpen返回的句柄
        // szServerHostName就是上面例子URL中的“myWebServer”
        // nPort是上例的8080,NULL的話表示默認(80)
        HINTERNET hConnection = ::InternetConnect(hInternet, szServerHostName, nPort, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
    3. 連接成功後,下面就開始發送請求,告訴服務器,我要上傳文件了。
        // szUrlPath就是上例中的“/Handler/FileUploader.aspx”,注意,最前面的"/"不能省略的。
        // accept是一個LPCTSTR數組,表示該URL接受的文件類型。可以用:
       //     LPCTSTR accept[] = {
       //         _T("*/*"),
       //         NULL
       //     };
       //    表示任何類型
        HINTERNET hRequest = ::HttpOpenRequest(hConnection, _T("POST"), szUrlPath, NULL, NULL, accept, 0, INTERNET_FLAG_EXISTING_CONNECT|INTERNET_FLAG_NO_AUTO_REDIRECT|INTERNET_FLAG_HYPERLINK);
        INTERNET_BUFFERS ib;
        memset(&ib, 0, sizeof(INTERNET_BUFFERS));
        ib.dwStructSize = sizeof(INTERNET_BUFFERS);
        ib.dwBufferTotal = dwTotalSize;    //這裏是你要傳送數據的總大小,比如一個文件的大小::GetFileSize(hFile, 0)
        ib.dwBufferLength = dwBufSize;    //分次上傳的話,每次上傳數據的大小,比如4裏面的dwBufSize

        ::HttpSendRequestEx(hRequest, &ib, 0, HSR_INITIATE, 0));

    4. 請求發送成功後,就可以傳送數據了,傳送數據使用的是::InternetWriteFile這個API
        DWORD dwBufSize = 1024*1024; //1M
        TCHAR* buffer = new TCHAR[dwBufSize];
        DWORD dwRead;
        ::InternetWriteFile(hRequest, buffer, dwBufSize, &dwRead);
        這樣就把數據發送到服務端了。
    5. 緊接着,客戶端需要調用HttpEndRequest()等待服務器處理。這個時候,客戶端的執行實際上是停止在這裏的,只有當服務段接受完數據,完成處理後,客戶端才接着執行下去。
    6. 下面就是釋放前面申請的句柄和內存了。

    以上是客戶端向服務器發送數據的全部過程了,如果想傳送文件的話,需要在4裏面,用一個循環,將文件數據不斷讀取到buffer裏,並用InternetWriteFile發送出去。
       
服務端:
    服務端就負責接收數據了,以下是C# asp.net的樣例。
    其實,也就是用Request不斷從管道里讀取上傳的數據。
    http://myWebServer:8080/Handler/FileUploader.aspx的cs文件

    FileUploader.cs文件
    
    public class FileUpload : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            Stream input = Request.InputStream;
            if (input.Length > 0)
            {
                String filepath = MapPath("~/Temp/UploadedFile.dat");
                using (FileStream output = File.Create(filepath))
                {
                    byte[] buffer = new byte[1024];
                    int nTotalBytesWritten = 0;
                    int nRead = input.Read(buffer, 0, buffer.Length);
                    while(nRead > 0)
                    {
                        output.Write(buffer, 0, nRead );
                        nTotalBytesWritten += nRead ;
                        nCount = input.Read(buffer, 0, buffer.Length);
                    }
                }
            }
        }
    }

注意事項:
    1. 上傳文件的大小還是受IIS限制的,大約超過1G之後,就Stream input = Request.InputStream;就會出現問題。如果要上傳超大文件,比如10G以上,這需要客戶端對文件進行處理,分塊上傳,最後服務端接收分塊,最後合併,還原。
    2. 不要在客戶端的HttpEndRequest()調用之前使用Session、Response、Request,在對話期間,這些變量都處於連接狀態,任何改變都是無效的(比如:Redirect(NewURL),Session這時候是不工作的)。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章