使用Java Socket发送HTTP响应时出现问题

4

我一直在努力编写一个简单的Web服务器,但似乎无法发送响应。 我尝试了各种类型的输出流,但似乎没有任何作用。 我很迷茫。 这是我正在使用的两个类,抱歉有些冗余代码:

package edu.xsi.webserver;

import java.io.IOException;
import java.net.ServerSocket;


public class WebServer {

int port;
ServerSocket server;

public WebServer(int port) throws IOException{

    this.port = port;
    this.server = new ServerSocket(port);
    Thread t = new Thread(new ServerExec());
    t.start();

}

public class ServerExec implements Runnable {

    public void run(){

        int i = 0;
        while (true) {

            try {
                new WebSession(server.accept(), i++);
                System.out.println("Should print before session");
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }


}

public static void main(String[] args) {

    try {
        WebServer webServer = new WebServer(8888);
    } catch (IOException e) {
        e.printStackTrace();
    }
}
}

这是处理响应的会话类。
package edu.xsi.webserver;

import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.Scanner;

public class WebSession implements Runnable {

Socket client;
int num;

public WebSession(Socket client, int num) {

    this.num = num;
    this.client = client;
    Thread t = new Thread(this);
    t.start();
}


public void run() {

    Scanner s = null;
    DataOutputStream out = null;

    try {

        s = new Scanner(client.getInputStream());
        out = new DataOutputStream(client.getOutputStream());

        //Get all input from header
        while (s.hasNextLine()) {
            System.out.println(s.nextLine());
        }
        out.writeBytes("HTTP/1.1 200 OK\r\n");
        out.writeBytes("Content-Type: text/html\r\n\r\n");
        out.writeBytes("<html><head></head><body><h1>Hello</h1></body></html>");

        s.close();
        out.flush();
        out.close();

    } catch(IOException ioe) {

        ioe.printStackTrace();
    }

}

}


1
服务器是否读取了客户端的所有输入?调试以查看它是否离开了while(s.hasNextLine())循环。 - jeff
哇,你说得对。我注释掉了 while 循环并得到了输出。显然我需要做更多的研究 :)。应该读取连续的 '\r\n' 集合。谢谢,这一直困扰着我。 - webhound
4个回答

15

我曾经也为类似的问题苦苦挣扎。

在一番头痛如裂的尝试后,我发现我的问题非常微不足道,但我还是继续头撞墙一段时间。

基本上,在我的输入循环中,我检查了一个空行,但我忘记了检查一个空白行(并随之跳出循环)。

不能保证这对您有用,但这是我的建议:

in = session.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String line = null;
while ((line = br.readLine()) != null) {
    System.out.println(line);
    // this seems to be the key for me! 
    // somehow I never get out of this loop if I don't 
    // check for an empty line...
    if (line.isEmpty()) {
        break;
    }
}
out = new BufferedWriter(
    new OutputStreamWriter(
        new BufferedOutputStream(session.getOutputStream()), "UTF-8")
);
out.write(OUTPUT_HEADERS + OUTPUT.length() + OUTPUT_END_OF_HEADERS + OUTPUT);
out.flush();
out.close();
session.close();

我的常量是:

private static final String OUTPUT = "<html><head><title>Example</title></head><body><p>Worked!!!</p></body></html>";
private static final String OUTPUT_HEADERS = "HTTP/1.1 200 OK\r\n" +
    "Content-Type: text/html\r\n" + 
    "Content-Length: ";
private static final String OUTPUT_END_OF_HEADERS = "\r\n\r\n";

我的“会话(session)”变量是一个Socket对象。


这在一般情况下是不起作用的。它适用于没有主体的GET请求,但通常您必须读取整个请求,而不仅仅是头文件,并且为此需要按照RFC 2616实现Content-length、chunked编码等。否则,当您关闭连接时,将重置连接。 - user207421

1
关闭Scanner会关闭底层输入流,从而关闭套接字。不要关闭它。关闭输出流也会关闭套接字。你不需要两个都关闭,而且你应该关闭输出流/写入器而不是输入流,这样它就会被刷新。

1
以下代码将解决您的问题:
package com.cs.sajal;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class TestCls {

    public static void main(String[] args) {
        boolean flag = false;

        try {
            ServerSocket ss = new ServerSocket(8080);
            if (ss.isBound()) {
                while (flag = true) {
                    final Socket s = ss.accept();



                    Thread t1=new Thread(new Runnable (){String line = null;public void run(){try{ InputStream is = s.getInputStream();
                    BufferedReader br = new BufferedReader(
                            new InputStreamReader(is));

                    while ((line = br.readLine()) != null) {
                        System.out.println(line);
                    }
                    }
                    catch(Exception e)
                    {
                        e.printStackTrace();
                    }
                    }});

                    Thread t2=new Thread(new Runnable (){String line = null;public void run(){try{ OutputStream os = s.getOutputStream();
                    Scanner sc=new Scanner(System.in);
                    String inp=null;
                    String t="HTTP/1.1 200 OK\r\n";
                    byte[]s=t.getBytes("UTF-8");
                    os.write(s);

                    t="Content-Length: 788\r\n";
                    s=t.getBytes("UTF-8");
                    os.write(s);
                    t="Content-Type: text/html\r\n\r\n";
                    s=t.getBytes("UTF-8");
                    os.write(s);


                    t="\r\n\r\n<html><body><h1>this is output</h1><table cellpading=5 border=5><tr><td>name</td><td>age></td><td>height</td></tr></table></body></html>\r\n\r\n";
                    s=t.getBytes("UTF-8");
                    os.write(s);
                    t="Connection: Closed";
                    s=t.getBytes("UTF-8");
                    os.write(s);

                    os.flush();
                    }
                    catch(Exception e)
                    {
                        e.printStackTrace();
                    }
                    }});
                    t1.start();
                    t2.start();t1.join();
                    t2.join();


                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

代码附加一些解释会很有帮助。 - Tot Zam

1
尝试传递日期。
 String res = "HTTP/1.0 200 OK\n"
         + "Server: HTTP server/0.1\n";
         + "Date: "+format.format(new java.util.Date())+"\n"; 
   + "Content-type: text/html; charset=UTF-8\n"; 
         + "Content-Length: 38\n\n";
         + "<html><body>OK</body></html>";
out.write(res.getBytes());
out.flush();

private SimpleDateFormat format = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:Ss z");

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接