天天看點

利用socket模拟http的混合表單上傳(在一個請求中送出表單并上傳多個檔案)

在很多企業級應用中,我們都沒法直接通過開發語言sdk包封裝的http工具來模拟http複合表單(multipart/form-data),特别是在跨語言跨平台的程式設計過程中,其實實作方案并不複雜,隻要你了解了http協定中複合表單的封包結構就很簡單了:

        httpheader

        ------時間戳------

        表單參數1

       ------時間戳------

       表單參數2

      ------時間戳------

      檔案1的描述+二進制資訊

     ------時間戳------

     檔案2的描述+二進制資訊

    下面我們進一步以一段c#的代執行個體碼來示範下這個結構:

        ///<summary>

        ///向伺服器發送混合型的請求,1:成功發送,0:發送失敗

        ///</summary>

        ///<param name="paranames">表單參數名數組</param>

        ///<param name="paravalues">參數值數組</param>

        ///<param name="files">檔案名數組</param>

        ///<param name="errmsg">報錯資訊</param>

        ///<returns></returns>

        public int sendrequest(string[] paranames, string[] paravalues, string[] files, ref string errmsg)

        {

            stringbuilder http, text;

            byte[] httpbyte;

            byte[] textbyte = null;

            long length = 0;

            datetime now = datetime.now;

            list<byte[]> data =new list<byte[]>();

            //構造時間戳

            string strboundary = "------------" + datetime.now.ticks.tostring("x");

            byte[] boundary = encoding.ascii.getbytes("\r\n" + strboundary +"\r\n");

            length += boundary.length;

            //加載表單參數資訊

            if (paranames != null)

            {

                text = new stringbuilder();

                for (int i = 0; i < paranames.length; i++)

                {

                    text.append("--");

                    text.append(strboundary);//添加時間戳

                    text.append("\r\n");

                    text.append("content-disposition: form-data; name=\"" + paranames[i] +"\"\r\n\r\n");

                    text.append(paravalues[i]);

                }

                string para = text.tostring();

                textbyte = encoding.ascii.getbytes(para);

                length += textbyte.length;

            }

            //加載檔案資訊

            if (files != null)

                for (int i = 0; i < files.length; i++)

                    filestream fs;

                    stringbuilder sbfile =new stringbuilder();

                    try

                    {

                        fs = file.open(files[i],filemode.open, fileaccess.read,fileshare.read);

                        if (i == 0) sbfile.append("--");//添加檔案

                        else sbfile.append("\r\n--");

                        sbfile.append(strboundary);//添加時間戳                       

                        sbfile.append("\r\n");

                        sbfile.append("content-disposition: form-data; name=\"");

                        sbfile.append("file");

                        sbfile.append("\"; filename=\"");

                        sbfile.append(path.getfilename(files[i]));

                        sbfile.append("\"");

                        sbfile.append("\r\n");

                        sbfile.append("content-type: ");

                        sbfile.append("application/octet-stream");

                        sbfile.append("\r\ncontent-length:");

                        sbfile.append(fs.length.tostring());

                        string temp = sbfile.tostring();

                        byte[] bin =encoding.utf8.getbytes(temp);

                        data.add(bin);

                        length += bin.length;

                        length += fs.length;

                        fs.close();

                    }

                    catch (exception exc)

                        errmsg = exc.message.tostring();

                        return 0;

            //構造http頭

            http = new stringbuilder();

            http.append("post " + ur.tostring() +" http/1.1\r\n");

            http.append("content-type:multipart/form-data;boundary=");

            http.append(strboundary);

            http.append("\r\n");

            http.append("host:" + ipaddress +":" + tcpport.tostring() + "\r\n");

            http.append("content-length:");

            http.append(length.tostring());

            http.append("expect: 100-continue\r\n");//注明要在收到伺服器的continue消息後才繼續上傳http消息體

            http.append("connection: keep-alive\r\n\r\n");

            string strtemp = http.tostring();

            httpbyte = encoding.ascii.getbytes(strtemp);

            try

                soc.send(httpbyte);"//首先發送http頭            

               thread.sleep(100);

                string check = getresponse();

                if (check == null || !check.contains("continue"))//得到伺服器确認後才繼續上傳

                    errmsg = "用戶端已成功發送請求,但伺服器沒有響應!";

                    return 0;

                if (paranames != null)

                    soc.send(textbyte, textbyte.length, socketflags.none);//發送表單參數

                if (files != null)

                {//依次發送檔案

                    for (int i = 0; i < data.count; i++)

                        int size = 0;

                        filestream fs =file.open(files[i], filemode.open, fileaccess.read, fileshare.read);

                        soc.send(data[i], data[i].length, socketflags.none);

                        byte[] buff =new byte[1024];

                        size = fs.read(buff, 0, 1024);

                        while (size > 0)

                        {

                            soc.send(buff, size, socketflags.none);

                            size = fs.read(buff, 0, 1024);

                        }

                soc.send(boundary, boundary.length, socketflags.none);

                return 1;

            catch (exception exc)

                errmsg = exc.message.tostring();

                return 0;

        }