天天看点

利用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;

        }