写了一个MyServer模拟http server 接收post请求。
java代码:package socket;import java.io.*;
import java.net.*;public class MyServer {
 public static void main(String args[]) throws Exception{
  ServerSocket serverSocket = new ServerSocket(8080);
  System.out.println("server is ok.");
  while(true){
   Socket socket = serverSocket.accept();
   BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
   String line = in.readLine();
   while(line!=null){
    System.out.println("Client: " + line);
    line = in.readLine();
   }
   System.out.println("current user close the session.");
   in.close();
   socket.close();
  }
 }
}
用浏览器打开下面的html文件,并提交数据:<head> 
<title>test my server</title> 
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 
</head> 
<body> 
<p>upload</p> 
<form name="UploadForm" method="post" action="http://localhost:8080/1.jsp">
<input type="text" name="myname" /><br>
<select name="myage">
  <option value="18">18</option>
  <option value="20">20</option>
  <option value="22">22</option>
</select><br>
<input type="submit"value="Sutmit">
</form>
</body> 
</html>MyServer打印出来的数据开始还正常:
server is ok.
Client: POST /testupload.jsp HTTP/1.1
Client: Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Client: Referer: http://localhost:8080/post.html
Client: Accept-Language: zh-cn
Client: User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)
Client: Content-Type: application/x-www-form-urlencoded
Client: Accept-Encoding: gzip, deflate
Client: Host: localhost:8080
Client: Content-Length: 28
Client: Connection: Keep-Alive
Client: Cache-Control: no-cache
Client:
走到这里的时候, 按http协议,接下来浏览器该传送post的数据了,但是程序走到这里就不走了。当我按esc之后,post数据才被提交上去
Client: myname=wwwwwwwwwwww&myage=18
current user close the session.很奇怪!
高手出来!

解决方案 »

  1.   

    有两个问题:1、因为你是readLine,最后的数据并没有回车换行,所以readLine就一直悬停了,你可以改成read(char[])这个方法试试,就能读到数据
    2、你在读到数据后,应该向客户端发出应答,否则客户端不会关闭Socket(除非超时,可能很长),这样你的程序还是会挂在那里不退出。
      

  2.   

    并不奇怪,
    readline要到文本行结尾才返回,
    但post提交的数据通过http消息体发送,末尾不必加换车符,
    所以此时readline就卡在那里了。空行是http头和消息体的分隔,
    可以在读到空行后,退出循环,转而用普通的读字符方式处理。
      

  3.   

    感谢1楼2楼。
    改成read(char[]), 但是问题还是没有消失,现在正在试验用2楼的方法!
      

  4.   

    为什么不用 httpClient 呢? 已经封装好了的..
      

  5.   

    我在写课件, 要给学生讲解socket编程实现简单的http get, post.
      

  6.   

    我晕,这都开始给学生讲课了啊,呵呵!
    对于原始数据的Socket发送,一定不要用readLine,否则以后会出现很多编码字符上的误解!
      

  7.   

    答:
    这是readLine()有缓冲。你直接使用字符流就行了。代码如下:Reader r=new InputStreamReader(socket.getInputStream());
       int ch;
       while((ch=r.read())!=-1){
        System.out.print((char)ch);
        }
       System.out.println("current user close the session.");
       r.close();
      

  8.   

    这样不行,因为-1代表流结束,而如果服务端不向客户端发送应答,流是不会结束的。
    答:楼主只要客户端发的数据能够一下子全显示出来,而不是readLine()那样显示不全就停止在那儿。这与“流是不会结束的”是没有关系的。只要数据能够一下子全显示出来,楼主的目的就达到了。
    关于流结束的问题,那是一个长连接,双方按HTTP协议来交互就行了[需要楼主解析HTTP头部内容],没有什么奥秘的。
      

  9.   

    我是用ie测试,向我写的HTTPServer提交请求。
    我觉得浏览器提交数据的方式应该是可靠的巴。
      

  10.   

    谢谢jiangnaisong, jinxfei,这个问题折腾了两天了。昨天回去重写代码,还是有一个大问题,我描述在程序中,谢谢再帮忙看看。package socket;import java.io.*;
    import java.net.ServerSocket;
    import java.net.Socket;public class MyHttpServer {
            //服务器根目录。post.html, upload.html都放在这里面。
    public static String WEB_ROOT = "c:/root";
    private int port;
            //请求的文件/url 路径
    private String requestPath;
            //处理multipart用的boundary 
    private String boundary = null;
            //post提交方式的数据长度
    private int contentLength = 0;
    public MyHttpServer(String root, int port) {
    WEB_ROOT = root;
    this.port = port;
    requestPath = null;
    } private void doGet(Socket socket) throws Exception {
    BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    if (new File(WEB_ROOT + this.requestPath).exists()) {
    InputStream fileIn = new FileInputStream(WEB_ROOT
    + this.requestPath);
    OutputStream out = socket.getOutputStream();
    byte[] buf = new byte[fileIn.available()];
    fileIn.read(buf);
    out.write(buf);
    out.close();
    fileIn.close();
    reader.close();
    socket.close();
    System.out.println("connection colsed");
    }
    } private void doPost(Socket socket, BufferedReader reader) throws Exception {
    //下面行出问题了, 如果不使用前面new的reader,用下面方式新开的reader读不到数据。
    //BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    String line = reader.readLine();
    while (line != null) {
    System.out.println(line);
    line = reader.readLine();
    if ("".equals(line)) {
    break;
    } else if (line.indexOf("Content-Length") != -1) {
    this.contentLength = Integer.parseInt(line.substring(line.indexOf("Content-Length") + 16));
    }
    //表明要上传附件, 跳转到doMultiPart方法。
    else if(line.indexOf("multipart/form-data")!= -1){
    //得multiltipart的分隔符
    this.boundary = line.substring(line.indexOf("boundary") + 9);
    this.doMultiPart(socket, reader);
    return;
    }
    }
    //继续读取普通post(没有附件)提交的数据
    System.out.println("begin read posted data......");
    char[] buf = null;
    if (this.contentLength != 0) {
    buf = new char[this.contentLength];
    reader.read(buf, 0, contentLength);
    System.out.println("The data user posted: " + new String(buf));
    }
    String response = "";
    response += "HTTP/1.1 200 OK\n";
    response += "Server: Sunpache 1.0\n";
    response += "Content-Type: text/html\n";
    response += "Last-Modified: Mon, 11 Jan 1998 13:23:42 GMT\n";
    response += "Accept-ranges: bytes";
    response += "\n";
    OutputStream out = socket.getOutputStream();
    //PrintWriter writer = new PrintWriter(socket.getOutputStream());
    //writer.write(response);
    String body = "<html><head><title>test server</title></head><body><p>post ok:</p>" + (new String(buf).replaceAll("&", "<br>")) + "</body></html>";
    System.out.println(body);

    //writer.write(body);
    //writer.flush();
    out.write(response.getBytes());
    out.write(body.getBytes());
    out.flush();
    reader.close();
    socket.close();
    } private void doMultiPart(Socket socket, BufferedReader reader) throws Exception {
    System.out.println("doMultiPart ......");
    String line = reader.readLine();
    while (line != null) {
    System.out.println(line);
    line = reader.readLine();
    if ("".equals(line)) {
    break;
    } else if (line.indexOf("Content-Length") != -1) {
    this.contentLength = Integer.parseInt(line.substring(line.indexOf("Content-Length") + 16));
    System.out.println("contentLength: " + this.contentLength);
    } else if (line.indexOf("boundary") != -1) {
    this.boundary = line.substring(line.indexOf("boundary") + 9);
    System.out.println("********" + boundary);
    }
    }
    System.out.println("begin get data......");
    if (this.contentLength != 0) {
    byte[] buf = new byte[this.contentLength];
    int totalRead = 0;
    int size = 0;
    while (totalRead < this.contentLength) {
    size = socket.getInputStream().read(buf, totalRead, this.contentLength - totalRead);
    totalRead += size;
    }
    System.out.println("totalRead: " + totalRead);
    String dataString = new String(buf, 0, totalRead);
    System.out.println("data posted:\n" + dataString);
                          //得到附件的开始位置和结束位置
    int pos = dataString.indexOf(boundary);
    System.out.println("pos: " + pos);
    pos = dataString.indexOf("\n", pos) + 1;
    System.out.println("pos: " + pos);
    pos = dataString.indexOf("\n", pos) + 1;
    System.out.println("pos: " + pos);
    pos = dataString.indexOf("\n", pos) + 1;
    System.out.println("pos: " + pos);
    pos = dataString.indexOf("\n", pos) + 1;
    int start = dataString.substring(0, pos).getBytes().length;
    pos = dataString.indexOf(boundary, pos) - 4;
    System.out.println("pos: " + pos);
    int end = dataString.substring(0, pos).getBytes().length;
                       //得到附件的文件名
    int fileNameBegin = dataString.indexOf("filename");
        System.out.println("fileNameBegin: " + fileNameBegin);
        int fileNameEnd = dataString.indexOf("\n", fileNameBegin);
        System.out.println("fileNameEnd:" + fileNameEnd);
        String fileName = dataString.substring(fileNameBegin, fileNameEnd);
        fileName = fileName.substring(fileName.lastIndexOf("\\") + 1);
        fileName = fileName.substring(0, fileName.length()-2);
        System.out.println("file Name------------>" + fileName);
        OutputStream fileOut = new FileOutputStream("c:\\" + fileName);
        fileOut.write(buf, start, end-start);
        fileOut.close();
    fileOut.close();
    }
    String response = "";
    response += "HTTP/1.1 200 OK\n";
    response += "Server: Sunpache 1.0\n";
    response += "Content-Type: text/html\n";
    response += "Last-Modified: Mon, 11 Jan 1998 13:23:42 GMT\n";
    response += "Accept-ranges: bytes";
    response += "\n";
    // response.getBytes(charsetName);
    OutputStream out = socket.getOutputStream();
    out.write("<html><head><title>test server</title></head><body><p>Post is ok</p></body></html>".getBytes());
    out.flush();
    reader.close();
    socket.close();
    System.out.println("session closed.");
    } public void service() throws Exception {
    ServerSocket serverSocket = new ServerSocket(this.port);
    System.out.println("server is ok.");
    while (true) {
    Socket socket = serverSocket.accept();
    System.out.println("new request coming.");
    BufferedReader reader = new BufferedReader(new InputStreamReader(
    socket.getInputStream()));
    reader.(1024);
    String line = reader.readLine();
    String method = line.substring(0, 4).trim();
    this.requestPath = line.split(" ")[1];
    System.out.println(method);
    if ("GET".equalsIgnoreCase(method)) {
    System.out.println("do get......");
    this.doGet(socket);
    } else if ("POST".equalsIgnoreCase(method)) {
    reader.reset();
    reader = null;
    System.out.println("do post......");
    this.doPost(socket, reader);
    }
    }
    } public static void main(String args[]) throws Exception {
    MyHttpServer server = new MyHttpServer("c:/root", 8080);
    server.service();
    }
    }post.html<html> 
    <head> 
    <title>test my server</title> 
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 
    </head> 
    <body> 
    <p>upload</p> 
     
    <form name="UploadForm" method="post" action="testupload.jsp">
    <input type="text" name="myname" /><br>
    <select name="myage">
      <option value="18">18</option>
      <option value="20">20</option>
      <option value="22">22</option>
    </select><br>
    <input type="submit"value="Sutmit">
    </form>
    </body> 
    </html>先不看有附件的情况,现在doGet方法可以work, doPost还有问题,我描述在方法里面。谢谢几位高手再看看。
      

  11.   

    答;楼主现在遇到的问题,我很清楚根源在何处。
    1)说一句可能楼主生气的话:楼主对socket流的用法不是很规范。原因是:每一个socket,关联一个输入流及输出流,
    当楼主转换成BufferedReader后,应将该br流传输到任何要用的方法中,而不是每一个方法中去分别创建流。
    2)现在楼主就是要在方法中分别创建流(像现在这种情形:在service()方法中创建一个socket对应
    的br流,在doPost()方法中对同一个socket,再创建一个socket对应的br流),又怎么样呢?
    这就会出现楼主现在遇到的这种情况:好像读不到数据了。其真正的原因是什么?
    是这样:
    每一个方法中所创建的br流,其底层是同一个InputStream流,当我们在service()方法中创建br流时[其实只要创建InputStreamReader流时],由于这些流内部都是有缓冲的,因而,一旦在service()方法中发生了读操作,立即会导致底层InputStream读入大量数据。[内部缓冲是8K],这时我们在doPost()方法中再创建br进行读取时,已被service()方法中读走
    的数据[8K],在doPost()中再也读不到了已被读走的数据。[只能读它之后的数据]这就是困绕楼主看到的情况[楼主误认为:好像是读不到数据了。]。对于楼主的情况,用()与reset()
    是没有用的--它只对楼的br流有用,但是:[因为底层InputStreamReader中使用了StreamDecoder,它有默认8K的BUF缓冲]。因此:
    结论:[怎么办?]
    1)若楼主在service()中,创建了br流,但没有发生读操作,则此时doPost()中再创建br流读取,将一切正常。
    2)若楼主在service()中,不创建任何底层内部带缓冲的流,直接使用原始的socket的InputStream进行
    读操作,则此时doPost()中再创建br流读取,也将一切正常。
    3)若楼主在service()中,创建任何底层内部带缓冲的流,即使使用()与reset(),因为它只是对内部带缓冲的流起作用,而不是对socket的InputStream起作用,一旦已发生读操作,则此时doPost()中再创建br流读取,将再也读不到了已被读走的数据。就会出现楼主现在遇到的这种情况:好像在doPost()读不到数据了。[其实不是,而是本来数据不多,
    已全被读走了。]
    4)规范的用法:一旦有了socket,创建它的I/O流,将该流传入到所有需要的方法中,而不是
    每一个方法都自己来再创建流。
      

  12.   

    jiangnaisong的回答我觉得淋漓尽致, 非常感谢你,就算冲着你打这么多字我都觉得给100分都少了。
    正在考虑是不是要新开一个帖子,你去签个名,我就把分数给你。
    我先按照你说的修改一下代码;
    但是我脑子里面还是有一个问题:
    对于简单的doGet和doPost(没有附件),用Reader就够用了。因为他们没有带二进制的数据;
    但是如果我要处理multipart的话,我必须要inputStream来读上传的文件,但同时我也要用Reader来读去开始的http头, 来解析一些必要的信息,
    因为这些信息是一行一行的发送的,如果用stream来读取这些信息我不知道怎么解析。
    DataInputStream既可以读行,也可以读byte, 但他的readLine不推荐使用了。
    总结出来就是我不知道怎么用stream来读一个完整的行,并判断行结束了。
      

  13.   

    我按照jiangnaisong的意思,改了程序, 因为考虑到要上传附件, 所以我用了DataInputStream, 虽然readLine方法已经推荐不使用,暂时将就一下。
    上传附件的问题解决了。但是现在post还是有一个问题, 我描述在程序中,谢谢大家再帮忙看看。
    MyHttpServer.javapackage socket;import java.io.*;
    import java.net.ServerSocket;
    import java.net.Socket;public class MyHttpServer {
    public static String WEB_ROOT = "c:/root";
    private int port;
    private String requestPath;
    private String boundary = null;
    private int contentLength = 0; public MyHttpServer(String root, int port) {
    WEB_ROOT = root;
    this.port = port;
    requestPath = null;
    } private void doGet(DataInputStream reader, OutputStream out) throws Exception {
    if (new File(WEB_ROOT + this.requestPath).exists()) {
    InputStream fileIn = new FileInputStream(WEB_ROOT + this.requestPath);
    byte[] buf = new byte[fileIn.available()];
    fileIn.read(buf);
    out.write(buf);
    out.close();
    fileIn.close();
    reader.close();
    System.out.println("connection colsed");
    }
    } private void doPost(DataInputStream reader, OutputStream out) throws Exception {
    //下面行出问题了, 如果不使用前面new的reader,用下面方式新开的reader读不到数据。
    String line = reader.readLine();
    while (line != null) {
    System.out.println(line);
    line = reader.readLine();
    if ("".equals(line)) {
    break;
    } else if (line.indexOf("Content-Length") != -1) {
    this.contentLength = Integer.parseInt(line.substring(line.indexOf("Content-Length") + 16));
    }
    //表明要上传附件, 跳转到doMultiPart方法。
    else if(line.indexOf("multipart/form-data")!= -1){
    //得multiltipart的分隔符
    this.boundary = line.substring(line.indexOf("boundary") + 9);
    this.doMultiPart(reader, out);
    return;
    }
    }
    //继续读取普通post(没有附件)提交的数据
    System.out.println("begin reading posted data......");
    String dataLine = null;
    //这里出问题了:如果提交普通的post(不带附件),程序走到这里不走了;就是说没有读到数据,
    //但是当我按浏览器ESC之后提交的数据正文就读出来了。
    //dataLine = reader.readLine();
    //我改为一个字符一个字符的读取也不可以。
    char[] buf = {};
    if (this.contentLength != 0) {
    buf = new char[this.contentLength];
    int size = 0;
    char c = reader.readChar();
    while(c!='\n'){
    buf[size++] = c;
    c = reader.readChar();
    }
    System.out.println("The data user posted: " + new String(buf, 0, size));
    }
    String response = "";
    response += "HTTP/1.1 200 OK\n";
    response += "Server: Sunpache 1.0\n";
    response += "Content-Type: text/html\n";
    response += "Last-Modified: Mon, 11 Jan 1998 13:23:42 GMT\n";
    response += "Accept-ranges: bytes";
    response += "\n";
    String body = "<html><head><title>test server</title></head><body><p>post ok:</p>" + new String(buf) + "</body></html>";
    System.out.println(body);
    out.write(response.getBytes());
    out.write(body.getBytes());
    out.flush();
    reader.close();
    out.close();
    } private void doMultiPart(DataInputStream reader, OutputStream out) throws Exception {
    System.out.println("doMultiPart ......");
    String line = reader.readLine();
    while (line != null) {
    System.out.println(line);
    line = reader.readLine();
    if ("".equals(line)) {
    break;
    } else if (line.indexOf("Content-Length") != -1) {
    this.contentLength = Integer.parseInt(line.substring(line.indexOf("Content-Length") + 16));
    System.out.println("contentLength: " + this.contentLength);
    } else if (line.indexOf("boundary") != -1) {
    //获取multipart分隔符
    this.boundary = line.substring(line.indexOf("boundary") + 9);
    }
    }
    System.out.println("begin get data......");
    /*下面的注释是一个浏览器发送带附件的请求的全文,所有中文都是说明性的文字*****
    <HTTP头部内容略>
    ............
    Cache-Control: no-cache
    <这里有一个空行,表明接下来的内容都是要提交的正文>
    -----------------------------7d925134501f6<这是multipart分隔符>
    Content-Disposition: form-data; name="myfile"; filename="mywork.doc"
    Content-Type: text/plain

    <附件正文>........................................
    .................................................

    -----------------------------7d925134501f6<这是multipart分隔符>
    Content-Disposition: form-data; name="myname"<其他字段或附件>
    <这里有一个空行>
    <其他字段或附件的内容>
    -----------------------------7d925134501f6--<这是multipart分隔符>
    ****************************************************************/
    /**
     * 上面的注释是一个带附件的multipart类型的POST的全文模型,
     * 要把附件去出来,就是要找到附件正文的起始位置和结束位置
     * **/
    if (this.contentLength != 0) {
    //把所有的提交的正文,包括附件和其他字段都先读到buf.
    byte[] buf = new byte[this.contentLength];
    int totalRead = 0;
    int size = 0;
    while (totalRead < this.contentLength) {
    size = reader.read(buf, totalRead, this.contentLength - totalRead);
    totalRead += size;
    }
    System.out.println("totalRead: " + totalRead);
    //用buf构造一个字符串,可以用字符串方便的计算出附件所在的位置
    String dataString = new String(buf, 0, totalRead);
    System.out.println("data posted:\n" + dataString);
    int pos = dataString.indexOf(boundary);
    //以下略过4行就是第一个附件的位置
    System.out.println("pos: " + pos);
    pos = dataString.indexOf("\n", pos) + 1;
    System.out.println("pos: " + pos);
    pos = dataString.indexOf("\n", pos) + 1;
    System.out.println("pos: " + pos);
    pos = dataString.indexOf("\n", pos) + 1;
    System.out.println("pos: " + pos);
    pos = dataString.indexOf("\n", pos) + 1;
    //附件开始位置
    int start = dataString.substring(0, pos).getBytes().length;
    pos = dataString.indexOf(boundary, pos) - 4;
    System.out.println("pos: " + pos);
    //附件结束位置
    int end = dataString.substring(0, pos).getBytes().length;
    //以下找出filename
    int fileNameBegin = dataString.indexOf("filename") + 10;
        int fileNameEnd = dataString.indexOf("\n", fileNameBegin);
        String fileName = dataString.substring(fileNameBegin, fileNameEnd);
        //
        if(fileName.lastIndexOf("\\")!=-1){
         fileName = fileName.substring(fileName.lastIndexOf("\\") + 1);
        }
        fileName = fileName.substring(0, fileName.length()-2);
        OutputStream fileOut = new FileOutputStream("c:\\" + fileName);
        fileOut.write(buf, start, end-start);
        fileOut.close();
    fileOut.close();
    }
    String response = "";
    response += "HTTP/1.1 200 OK\n";
    response += "Server: Sunpache 1.0\n";
    response += "Content-Type: text/html\n";
    response += "Last-Modified: Mon, 11 Jan 1998 13:23:42 GMT\n";
    response += "Accept-ranges: bytes";
    response += "\n";
    out.write("<html><head><title>test server</title></head><body><p>Post is ok</p></body></html>".getBytes());
    out.flush();
    reader.close();
    System.out.println("session closed.");
    } public void service() throws Exception {
    ServerSocket serverSocket = new ServerSocket(this.port);
    System.out.println("server is ok.");
    while (true) {
    Socket socket = serverSocket.accept();
    System.out.println("new request coming.");
    DataInputStream reader = new DataInputStream((socket.getInputStream()));
    String line = reader.readLine();
    String method = line.substring(0, 4).trim();
    OutputStream out = socket.getOutputStream();
    this.requestPath = line.split(" ")[1];
    System.out.println(method);
    if ("GET".equalsIgnoreCase(method)) {
    System.out.println("do get......");
    this.doGet(reader, out);
    } else if ("POST".equalsIgnoreCase(method)) {
    System.out.println("do post......");
    this.doPost(reader, out);
    }
    socket.close();
    }
    }
    public static void main(String args[]) throws Exception {
    MyHttpServer server = new MyHttpServer("c:/root", 8080);
    server.service();
    }
    }upload.html: <测试上传附件用><html>
    <head>
    <title>my page</title>
    <style>
      table{
        border-collapse: collapse;
      }
    </style>
    </head>
    <body>
    <form action='http://localhost:8080' method='post' enctype='multipart/form-data'>
    file: <input type='file' name='myfile' /><br>
    name: <input type='text' name='myname' /><br>
    <input type='submit' />
    </form>
    </body>
    </html>post.html和13楼一样<测试普通post用>
      

  14.   

    答:首先真心谢谢楼主的关照。
    确实是这样,处理HTTP头,需要字符流,但处理数据部分,需要字节流,怎么办?
    实际上,HTTP协议是建立在字节流基础之上的。即:HTTP协议明确规定每一行是以CRLF结束的(即ACSII码13与ACSII码10)。因此:我想:可能的话,还是以字节流统一处理HTTP头部[因为:只有ASCII字符,不会有汉字的]。这样做的目的是:处理HTTP BODY部分时,只能是字节流。,因而HTTP头部与HTTP BODY就可以统一处理了。为什么在处理HTTP头部时,不能用BufferedReader来处理?还是那个缓冲问题。[它会把BODY部分的字节数据以字符流方式预先读入进来,这就会造成:以字符流方式处理字节流的HTTP BODY,可能会有问题]。以上仅供楼主参考
      

  15.   

    新开的散分贴,欢迎上面各位热心的朋友去签名,签名就给分,谢谢。
    http://topic.csdn.net/u/20090627/22/4b19638d-378c-4fcd-bf7e-8536903ef9c8.htmlhttp://topic.csdn.net/u/20090627/22/4b19638d-378c-4fcd-bf7e-8536903ef9c8.html
      

  16.   

    答:
    1)楼主的整个doPost()与doMultiPart()没有严格按HTTP协议来写,这会有问题的。我认为要重新写。
    2)现在首先针对楼主的那个小问题:“这里出问题了:如果提交普通的post(不带附件),程序走到这里不走了;就是说没有读到数据,”,原因或根源是什么?
    还是因为楼主的代码没有按HTTP协议的规定要求写。将dopost()中的代码://这里出问题了:如果提交普通的post(不带附件),程序走到这里不走了;就是说没有读到数据,
            //但是当我按浏览器ESC之后提交的数据正文就读出来了。
            //dataLine = reader.readLine();
            //我改为一个字符一个字符的读取也不可以。
            char[] buf = {};
            if (this.contentLength != 0) {
                buf = new char[this.contentLength];
                int size = 0;
                char c = reader.readChar();
                while(c!='\n'){
                    buf[size++] = c;
                    c = reader.readChar();
                }
                System.out.println("The data user posted: " + new String(buf, 0, size));
            }
    改为: byte[] buf = {};
            if (this.contentLength != 0) {
                buf = new byte[this.contentLength];
                int size = 0;
                
                while(size<this.contentLength){
                 int c = reader.read();
                    buf[size++] = (byte)c;
                    
                }
                System.out.println("The data user posted: " + new String(buf, 0, size));
            }则这个小问题就解决了。但我认为:整个doPost()与doMultiPart()要严格按HTTP协议来重写,这才是解决问题的根本之道。
      

  17.   

    问题真的解决了, 这次真的学到了很多东西。jiangnaisong, 你是真正的专家,小弟佩服。 我加你的好友了。不知可否?
      

  18.   

    下去我会用字节流重写代码,不过暂时就不写了,本来想写解析多附件,但是现在也没有时间了。马上要开课了。还要准备其他的内容。
    早上起来发现帖子被推荐了。幸福啊, 第一次耶。感谢版主。
    代码我都贴出来,真的很感谢jiangnaisong, jinxfei ,dengsf,以及其他的帮忙盖楼的朋友。
    有兴趣的人看到代码,可以遵照http协议重写一下,如果有看不明白的地方,请回头看完整的帖子和http协议,其实这个东西实用性等于0, 但是可以大大的了解http协议。
    然后其他的应用层协议大都如此。package socket;import java.io.*;
    import java.net.*;
    /**
     * MyHttpServer 实现一个简单的HTTP服务器端,可以获取用户提交的内容
     * 并给用户一个response
     * 因为时间的关系,对http头的处理显得不规范
     * 对于上传附件,暂时只能解析只上传一个附件而且附件位置在第一个的情况
     * 转载请注明来自http://blog.csdn.net/sunxing007
     * **/
    public class MyHttpServer {
    //服务器根目录,post.html, upload.html都放在该位置
    public static String WEB_ROOT = "c:/root";
    //端口
    private int port;
    //用户请求的文件的url
    private String requestPath;
    //mltipart/form-data方式提交post的分隔符, 
    private String boundary = null;
    //post提交请求的正文的长度
    private int contentLength = 0; public MyHttpServer(String root, int port) {
    WEB_ROOT = root;
    this.port = port;
    requestPath = null;
    }
    //处理GET请求
    private void doGet(DataInputStream reader, OutputStream out) throws Exception {
    if (new File(WEB_ROOT + this.requestPath).exists()) {
    //从服务器根目录下找到用户请求的文件并发送回浏览器
    InputStream fileIn = new FileInputStream(WEB_ROOT + this.requestPath);
    byte[] buf = new byte[fileIn.available()];
    fileIn.read(buf);
    out.write(buf);
    out.close();
    fileIn.close();
    reader.close();
    System.out.println("request complete.");
    }
    }
    //处理post请求
    private void doPost(DataInputStream reader, OutputStream out) throws Exception {
    String line = reader.readLine();
    while (line != null) {
    System.out.println(line);
    line = reader.readLine();
    if ("".equals(line)) {
    break;
    } else if (line.indexOf("Content-Length") != -1) {
    this.contentLength = Integer.parseInt(line.substring(line.indexOf("Content-Length") + 16));
    }
    //表明要上传附件, 跳转到doMultiPart方法。
    else if(line.indexOf("multipart/form-data")!= -1){
    //得multiltipart的分隔符
    this.boundary = line.substring(line.indexOf("boundary") + 9);
    this.doMultiPart(reader, out);
    return;
    }
    }
    //继续读取普通post(没有附件)提交的数据
    System.out.println("begin reading posted data......");
    String dataLine = null;
    //用户发送的post数据正文
    byte[] buf = {};
    int size = 0;
            if (this.contentLength != 0) {
                buf = new byte[this.contentLength];
                while(size<this.contentLength){
                    int c = reader.read();
                    buf[size++] = (byte)c;
                    
                }
                System.out.println("The data user posted: " + new String(buf, 0, size));
            }
            //发送回浏览器的内容
    String response = "";
    response += "HTTP/1.1 200 OK\n";
    response += "Server: Sunpache 1.0\n";
    response += "Content-Type: text/html\n";
    response += "Last-Modified: Mon, 11 Jan 1998 13:23:42 GMT\n";
    response += "Accept-ranges: bytes";
    response += "\n";
    String body = "<html><head><title>test server</title></head><body><p>post ok:</p>" + new String(buf, 0, size) + "</body></html>";
    System.out.println(body);
    out.write(response.getBytes());
    out.write(body.getBytes());
    out.flush();
    reader.close();
    out.close();
    System.out.println("request complete.");
    }
    //处理附件
    private void doMultiPart(DataInputStream reader, OutputStream out) throws Exception {
    System.out.println("doMultiPart ......");
    String line = reader.readLine();
    while (line != null) {
    System.out.println(line);
    line = reader.readLine();
    if ("".equals(line)) {
    break;
    } else if (line.indexOf("Content-Length") != -1) {
    this.contentLength = Integer.parseInt(line.substring(line.indexOf("Content-Length") + 16));
    System.out.println("contentLength: " + this.contentLength);
    } else if (line.indexOf("boundary") != -1) {
    //获取multipart分隔符
    this.boundary = line.substring(line.indexOf("boundary") + 9);
    }
    }
    System.out.println("begin get data......");
    /*下面的注释是一个浏览器发送带附件的请求的全文,所有中文都是说明性的文字*****
    <HTTP头部内容略>
    ............
    Cache-Control: no-cache
    <这里有一个空行,表明接下来的内容都是要提交的正文>
    -----------------------------7d925134501f6<这是multipart分隔符>
    Content-Disposition: form-data; name="myfile"; filename="mywork.doc"
    Content-Type: text/plain

    <附件正文>........................................
    .................................................

    -----------------------------7d925134501f6<这是multipart分隔符>
    Content-Disposition: form-data; name="myname"<其他字段或附件>
    <这里有一个空行>
    <其他字段或附件的内容>
    -----------------------------7d925134501f6--<这是multipart分隔符,最后一个分隔符多两个->
    ****************************************************************/
    /**
     * 上面的注释是一个带附件的multipart类型的POST的全文模型,
     * 要把附件去出来,就是要找到附件正文的起始位置和结束位置
     * **/
    if (this.contentLength != 0) {
    //把所有的提交的正文,包括附件和其他字段都先读到buf.
    byte[] buf = new byte[this.contentLength];
    int totalRead = 0;
    int size = 0;
    while (totalRead < this.contentLength) {
    size = reader.read(buf, totalRead, this.contentLength - totalRead);
    totalRead += size;
    }
    //用buf构造一个字符串,可以用字符串方便的计算出附件所在的位置
    String dataString = new String(buf, 0, totalRead);
    System.out.println("the data user posted:\n" + dataString);
    int pos = dataString.indexOf(boundary);
    //以下略过4行就是第一个附件的位置
    pos = dataString.indexOf("\n", pos) + 1;
    pos = dataString.indexOf("\n", pos) + 1;
    pos = dataString.indexOf("\n", pos) + 1;
    pos = dataString.indexOf("\n", pos) + 1;
    //附件开始位置
    int start = dataString.substring(0, pos).getBytes().length;
    pos = dataString.indexOf(boundary, pos) - 4;
    //附件结束位置
    int end = dataString.substring(0, pos).getBytes().length;
    //以下找出filename
    int fileNameBegin = dataString.indexOf("filename") + 10;
        int fileNameEnd = dataString.indexOf("\n", fileNameBegin);
        String fileName = dataString.substring(fileNameBegin, fileNameEnd);
        /**
         * 有时候上传的文件显示完整的文件名路径,比如c:\my file\somedir\project.doc
         * 但有时候只显示文件的名字,比如myphoto.jpg.
         * 所以需要做一个判断。
        */
        if(fileName.lastIndexOf("\\")!=-1){
         fileName = fileName.substring(fileName.lastIndexOf("\\") + 1);
        }
        fileName = fileName.substring(0, fileName.length()-2);
        OutputStream fileOut = new FileOutputStream("c:\\" + fileName);
        fileOut.write(buf, start, end-start);
        fileOut.close();
    fileOut.close();
    }
    String response = "";
    response += "HTTP/1.1 200 OK\n";
    response += "Server: Sunpache 1.0\n";
    response += "Content-Type: text/html\n";
    response += "Last-Modified: Mon, 11 Jan 1998 13:23:42 GMT\n";
    response += "Accept-ranges: bytes";
    response += "\n";
    out.write("<html><head><title>test server</title></head><body><p>Post is ok</p></body></html>".getBytes());
    out.flush();
    reader.close();
    System.out.println("request complete.");
    } public void service() throws Exception {
    ServerSocket serverSocket = new ServerSocket(this.port);
    System.out.println("server is ok.");
    //开启serverSocket等待用户请求到来,然后根据请求的类别作处理
    //在这里我只针对GET和POST作了处理
    //其中POST具有解析单个附件的能力
    while (true) {
    Socket socket = serverSocket.accept();
    System.out.println("new request coming.");
    DataInputStream reader = new DataInputStream((socket.getInputStream()));
    String line = reader.readLine();
    String method = line.substring(0, 4).trim();
    OutputStream out = socket.getOutputStream();
    this.requestPath = line.split(" ")[1];
    System.out.println(method);
    if ("GET".equalsIgnoreCase(method)) {
    System.out.println("do get......");
    this.doGet(reader, out);
    } else if ("POST".equalsIgnoreCase(method)) {
    System.out.println("do post......");
    this.doPost(reader, out);
    }
    socket.close();
    System.out.println("socket closed.");
    }
    }
    public static void main(String args[]) throws Exception {
    MyHttpServer server = new MyHttpServer("c:/root", 8080);
    server.service();
    }
    }
      

  19.   

    测试文件:
    post.html:测试提交的普通post请求.<html> 
    <head> 
    <title>test my server</title> 
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 
    </head> 
    <body> 
    <p>upload</p> <form name="UploadForm" method="post" action="testupload.jsp">
    <input type="text" name="myname" /><br>
    <select name="myage">
      <option value="18">18</option>
      <option value="20">20</option>
      <option value="22">22</option>
    </select><br>
    <input type="submit"value="Sutmit">
    </form>
    </body> 
    </html>upload.html:测试带一个附件的post.<head>
    <title>my page</title>
    <style>
      table{
        border-collapse: collapse;
      }
    </style>
    </head>
    <body>
    <form action='submit.jsp' method='post' enctype='multipart/form-data'>
    file: <input type='file' name='myfile' /><br>
    <input type='submit' />
    </form>
    </body>
    </html>
      

  20.   

    学习了 
    自己这段时间也准备复习socket,这个老师好啊,我们的老师上课都是照着课本读了一下,就结束了。
      

  21.   


    InputStream is = socket.getInputStream();
      

  22.   

    关于 java实现http协议服务器端 比较详细的文档我放在blog里面
    http://blog.csdn.net/sunxing007/archive/2009/06/29/4305956.aspx
      

  23.   

    楼主!
    我是用J2ME调用怎么response返回的信息都是空的
    我是调用你的例子
    还有没有一些HTTP开发的标准协议规范没?
    如果有能发给我的Emial:[email protected]
    谢谢
      

  24.   

    昨天刚犯了和楼主一样的错误,将socket丢给另外的方法,再重新new一个新的的ObjectOutputStream就出问题了,学习了,很有帮助
      

  25.   

    import java.io.File;
    public class msbTree {
    public static void main(String[] args){
    File file = new File("C:/Documents and Settings/Admini" +
    "strator/workspace/FileTree/src/a");
    System.out.println(file.getName());
    tree(file,1);
    }

    public static void tree(File file,int level){
    String fr = "";
    for(int k=0;k<level;k++){
    fr += "      ";
    }
    File[] children = file.listFiles();
    for(int i=0;i<children.length ;i++){
    System.out.println(fr+"/"+children[i].getName());
    if(children[i].isDirectory()&&children[i].listFiles()!=null){
    tree(children[i],++level);
    }

    }
    }
    }
      

  26.   

    我想弱弱的问下,为什么 ,提交后回进入MyHttpServer 这个类啊。你告诉我吧。谢谢。