用Socket实现HTTP文件上传

我想做过web开发的程序员大部分都做过文件上传的功能,大多数时候我们都是借助于commons-fileupload这样的jar包实现的。下面我试着通过读取Socket的输入流来实现一个文件上传的功能。

在做文件上传之前我们需要先了解一下HTTP POST的附件上传协议。HTTP附件上传协议是RFC1876协议,RFC1876协议是在HTTP协议的基础上为INPUT标签增加了file属性,同时限定了Form的method必须为POST,ENCTYPE必须为multipart/form-data。RFC1867协议对HTTP头作了适当地变更,content-type头由以前的:content-type:application/x-www-form-urlencoded变为content-type:multipart/form-data;+空格+boundary=字符串。RFC1867增加了文件上传得功能,而上传文件内容自然也会被加入到HTTP的实体中。现在因为既有HTTP一般的参数实体,又有上传文件的实体,所以用boundary把每种实体进行了分割。具体的看下图:

接下来就开始我们的代码部分吧。

我在前面的文章中写过创建一个自己的Web服务器,我们在这篇文章中还是使用上次创建的服务器如果不知道这篇文章在哪里的话,请点击这里。现在我们的重点要放在对socket的输入流的解析中。具体代码如下:

    public void parseRequest() {
        LineNumberReader br = new LineNumberReader(new InputStreamReader(inputStream));
        StringBuffer sb = new StringBuffer();
        String str = null;
        try {
            //读取请求行
            String requestLine = br.readLine();
            if (!StringUtils.isEmpty(requestLine)) {
                sb.append(requestLine);
                String[] reqs = requestLine.split(" ");
                if (reqs != null && reqs.length > 0) {
                    if ("GET".equals(reqs[0])) {
                        method = "GET";
                    } else {
                        method = "POST";
                    }
                }
            }
            //读取请求头
            while ((str = br.readLine()) != null) {
                if ("".equals(str)) {
                    break;
                }
                if (!StringUtils.isEmpty(str)) {
                    if (str.indexOf(":") > 0) {
                        String[] strs = str.split(":");
                        headers.put(strs[0].toLowerCase(), strs[1].trim());
                    }
                }
                sb.append(str).append("\n");
            }
            //POST请求,Content-type为 multipart/form-data
            String contentType = null;
            if ("POST".equals(method) && ((contentType = headers.get("content-type")) != null
                    && headers.get("content-type").startsWith("multipart/form-data"))) {
                //文件上传的分割位 这里只处理单个文件的上传
                String boundary = contentType.substring(contentType.indexOf("boundary") +
                        "boundary=".length());
                //解析消息体
                while ((str = br.readLine()) != null) {
                    //解析结束的标记
                    do {
                        //读取boundary中的内容
                        //读取Content-Disposition
                        str = br.readLine();
                        //说明是文件上传
                        if (str.indexOf("Content-Disposition:") >= 0 && str.indexOf("filename") > 0) {
                            str = str.substring("Content-Disposition:".length());
                            String[] strs = str.split(";");
                            String fileName = strs[strs.length - 1].replace("\"", "").split("=")[1];
                            System.out.println("fileName = " + fileName);
                            //这一行是Content-Type
                            br.readLine();
                            //这一行是换行
                            br.readLine();
                            //正式去读文件的内容
                            BufferedWriter bw = null;
                            try {
                                bw = new BufferedWriter(new OutputStreamWriter(new
                                        FileOutputStream("G:\\LearnVideo\\fileLoad" +
                                        File.separator + fileName), "UTF-8"));
                                while (true) {
                                    str = br.readLine();
                                    if (str.startsWith("--" + boundary)) {
                                        break;
                                    }
                                    bw.write(str);
                                    bw.newLine();
                                }
                                bw.flush();
                            } catch (Exception e) {

                            } finally {
                                if (bw != null) {
                                    bw.close();
                                }
                            }
                        }
                        if (str.indexOf("Content-Disposition:") >= 0) {
                            str = str.substring("Content-Disposition:".length());
                            String[] strs = str.split(";");
                            String name = strs[strs.length - 1].replace("\"", "").split("=")[1];
                            br.readLine();
                            StringBuilder stringBuilder = new StringBuilder();
                            while (true) {
                                str = br.readLine();
                                if (str.startsWith("--" + boundary)) {
                                    break;
                                }
                                stringBuilder.append(str);
                            }
                            parameters.put(name, stringBuilder.toString());
                        }
                    } while (("--" + boundary).equals(str));
                    //解析结束
                    if (str.equals("--" + boundary + "--")) {
                        break;
                    }
                }
            }
            //System.out.println(sb.toString());
            //获取URI
            uri = StringUtils.parserUri(sb.toString(), " ");
            int flag = -1;
            //说明有参数
            if ((flag = uri.indexOf('?')) >= 0) {
                String oldUri = uri;
                uri = uri.substring(0,flag);
                String parameterPath = oldUri.substring(flag+1);
                String[] parameter = parameterPath.split("&");
                if (parameter != null && parameter.length > 0) {
                    for (int i = 0; i < parameter.length; i++) {
                        String str1 = parameter[i];
                        if((flag = str1.indexOf('=')) >= 0){
                            String key = str1.substring(0,flag);
                            String value = str1.substring(flag+1);
                            parameters.put(key,value);
                        }else{
                            parameters.put(str,null);
                        }
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

我们启动自己创建的Web服务器,然后在浏览器中输入:http://localhost:8004/static/uploadPage.html,页面如下:

选择我们要上次的文件,然后点击上传按钮,我们会发现我们的功能已经被上传到G:\LearnVideo\fileLoad这个目录下了。示例如下:

完整的代码请从这里下载:http://download.csdn.net/detail/zknxx/9774786

时间: 2024-08-01 17:45:49

用Socket实现HTTP文件上传的相关文章

VB.Net Socket实现Http文件上传及下载类如何使用

问题描述 VB.Net Socket实现Http文件上传及下载类如何使用 门外汉求指教. 1.平台:SQL 2008 & appserv & mysql,VS2010 2.问题:①为实现文件上传.下载功能: ②参照了http://www.newxing.com/Tech/DotNet/VBDotNet/Socket_213.html 3.提问:①已添加上述网站中WebClient模块,现调用httpClient.UploadFile httpClient.DownLoadFile,WinF

flex socket 文件上传-求助大神,使用flex+socket上传超过2G的文件

问题描述 求助大神,使用flex+socket上传超过2G的文件 目前我有个项目中需要使用flex+socket把2G以上的文件上传到服务器,但是flex里面的FileRefrence中的load方法最大支持100M,在网上找到都是通过flex中的upload()方法+servlet来实现的,但是使用servlet的话http协议应该就只能支持2G以下的了.请各位有研究过的大神给点意见或者例子之类的,小弟在这里感激不尽哇!!!

Java Socket+mysql实现简易文件上传器的代码_java

最近跟着某网站学习了一个小项目,因为白天有课,所以都是晚上写的,今天把它完成了. 项目主要是实现一个文件上传器,通过客户端的登陆,把本地文件上传到服务器的数据库(本地的). 首先建两个表如下: 一个文件信息表 CREATE TABLE `fileinfo` ( `Fname` char(50) NOT NULL, `FInfo` blob NOT NULL, `FId` int(10) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`FId`) ) ENGINE=I

利用java Socket文件上传/进度条实现代码

1.客户端运行程序:  代码如下 复制代码 package wtb.khd; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.OutputStream; import java.net.Socket;

java web-socket多客户端同时文件上传

问题描述 socket多客户端同时文件上传 现在有javaweb服务端和C#客户端 C#客户端用于数据文件上传,文件上传方式使用socket,现在遇到的问题是: 如果多个客户端同时进行文件上传,则一个客户端数据上传时,其他客户端则无法上传, 一直处于等待状态. 如何解决,跪求! 解决方案 貌似一个socket监听,做服务.有新的连接就再开一个socket与新的连接通信.原socket继续监听-- 解决方案二: 你用的链接模型不支持把可能,或者弄成异步的?

Java 文件上传下载管理器(控制台)

文件上传下载管理器项目技术 JDBC + IO + Socket 实现功能 客户端注册:通过输入用户名,密码,确认密码并且校验完成以后将用户信息储存在数据库中. 客户端登录:通过输入用户名和密码到数据库中校验,校验完成进入文件上传下载管理器. 上传文件:通过输入上传文件的路径上传到数据库,支持多个文件上传. 查看文件:通过登录的用户名查找上传的文件. 下载文件:通过输入文件的编号和下载的路径,从数据库进行下载. 删除文件:通过输入文件的编号进行单个文件的删除. (ps:这次花了一天才写完,不过收

PHP利用APC模块实现大文件上传进度条的方法_php技巧

php 大文件带进度的上传,一直是一个令php程序员很苦恼的问题.查询baidu .Google ,大体做带进度的上传方式为:flash+php,socket,apc+php等,下面我介绍了apc +php+ajax制作的带进度的上传,并贴出源码,希望对大家有用. Alternative PHP Cache(APC)是 PHP 的一个免费公开的优化代码缓存.它用来提供免费,公开并且强健的架构来缓存和优化 PHP 的中间代码.  在使用apc时候,先必须使用安装apc 模块.第一步:下载php_a

PHP文件上传问题汇总(文件大小检测、大文件上传处理)_php技巧

由于涉及到本地和服务器两方面的安全问题,所以基于input type="file"形式的页面文件上传一直处于一个很尴尬的位置.一方面,用户不希望隐私泄露,所以浏览器无法对用户在上传时选择的文件做有效的判 断.另一方面,为了服务器端的安全,减轻传输负担,系统又希望能在用户开始上传之前就将非法的文件拒之门外. 一来一去,基于原始input方式的上传,成为网络存储网站避之唯恐不及的遗留性问题,也造就了现在千奇百怪的插件.上传客户端. input方式的上传就如此之差么?当然不是.上传文件不大的

Java实现FTP批量大文件上传下载篇1_java

本文介绍了在Java中,如何使用Java现有的可用的库来编写FTP客户端代码,并开发成Applet控件,做成基于Web的批量.大文件的上传下载控件.文章在比较了一系列FTP客户库的基础上,就其中一个比较通用且功能较强的j-ftp类库,对一些比较常见的功能如进度条.断点续传.内外网的映射.在Applet中回调JavaScript函数等问题进行详细的阐述及代码实现,希望通过此文起到一个抛砖引玉的作用. 一.引子 笔者在实施一个项目过程中出现了一种基于Web的文件上传下载需求.在全省(或全国)各地的用