Java服务器:使用Socket向浏览器发送HTML代码

5

我正在尝试使用ServerSockets编写一个简单的Java程序,向浏览器发送一些HTML代码。这是我的代码:

ServerSocket serverSocket = null;
try {
    serverSocket = new ServerSocket(55555); 
} catch (IOException e) {
    System.err.println("Could not listen on port: 55555.");
    System.exit(1);
}

Socket clientSocket = null; 
try {
    clientSocket = serverSocket.accept();

    if(clientSocket != null) {           
        System.out.println("Connected");
    }
} catch (IOException e) {
    System.err.println("Accept failed.");
    System.exit(1);
}

PrintWriter out = new PrintWriter(clientSocket.getOutputStream());


out.println("HTTP/1.1 200 OK");
out.println("Content-Type: text/html");
out.println("\r\n");
out.println("<p> Hello world </p>");
out.flush();

out.close();

clientSocket.close();
serverSocket.close();

我在浏览器中输入localhost:55555,但没有内容显示。我知道连接是正常的,因为程序输出“已连接”,并已通过if语句进行检查。我还尝试从inputStream输出数据,并且它起作用了。但是,我想在浏览器中输出的文本根本没有显示出来,程序运行结束,我的浏览器会显示:

"问题加载页面 - 连接已被重置"

但是没有任何文本。

我在网上搜索过,似乎所有以这种方式编码的其他人都能正确显示其文本,他们遇到了其他问题。我该如何解决呢?


你测试用的是哪个浏览器?这段代码在我的Chrome和Firefox里都可以正常运行。 - fmodos
在Chrome中,我甚至没有从inputStream得到任何结果。 - ALR
6个回答

4

我在Chrome、Firefox、IE和Opera中测试了你的代码,它可以正常工作。

然而,我建议你使用多线程,基本上为每个新请求生成一个新线程来处理。

你可以创建一个实现runnable接口并在构造函数中传入clientSocket的类。这将使你的自定义Web服务器能够同时接受多个请求。

如果你想处理多个请求,还需要一个while循环。

以下是一个很好的阅读材料,展示了上述内容:https://web.archive.org/web/20130525092305/http://www.prasannatech.net/2008/10/simple-http-server-java.html

如果Web Archive无法访问,我会在下面发布代码(取自上述网站):

/*
* myHTTPServer.java
* Author: S.Prasanna
* @version 1.00
*/

import java.io.*;
import java.net.*;
import java.util.*;

public class myHTTPServer extends Thread {

static final String HTML_START =
"<html>" +
"<title>HTTP Server in java</title>" +
"<body>";

static final String HTML_END =
"</body>" +
"</html>";

Socket connectedClient = null;
BufferedReader inFromClient = null;
DataOutputStream outToClient = null;


public myHTTPServer(Socket client) {
connectedClient = client;
}

public void run() {

try {

System.out.println( "The Client "+
  connectedClient.getInetAddress() + ":" + connectedClient.getPort() + " is connected");

  inFromClient = new BufferedReader(new InputStreamReader (connectedClient.getInputStream()));
  outToClient = new DataOutputStream(connectedClient.getOutputStream());

String requestString = inFromClient.readLine();
  String headerLine = requestString;

  StringTokenizer tokenizer = new StringTokenizer(headerLine);
String httpMethod = tokenizer.nextToken();
String httpQueryString = tokenizer.nextToken();

StringBuffer responseBuffer = new StringBuffer();
responseBuffer.append("<b> This is the HTTP Server Home Page.... </b><BR>");
  responseBuffer.append("The HTTP Client request is ....<BR>");

  System.out.println("The HTTP request string is ....");
  while (inFromClient.ready())
  {
    // Read the HTTP complete HTTP Query
    responseBuffer.append(requestString + "<BR>");
System.out.println(requestString);
requestString = inFromClient.readLine();
}

if (httpMethod.equals("GET")) {
if (httpQueryString.equals("/")) {
 // The default home page
sendResponse(200, responseBuffer.toString(), false);
} else {
//This is interpreted as a file name
String fileName = httpQueryString.replaceFirst("/", "");
fileName = URLDecoder.decode(fileName);
if (new File(fileName).isFile()){
sendResponse(200, fileName, true);
}
else {
sendResponse(404, "<b>The Requested resource not found ...." +
"Usage: http://127.0.0.1:5000 or http://127.0.0.1:5000/</b>", false);
}
}
}
else sendResponse(404, "<b>The Requested resource not found ...." +
"Usage: http://127.0.0.1:5000 or http://127.0.0.1:5000/</b>", false);
} catch (Exception e) {
e.printStackTrace();
}
}

public void sendResponse (int statusCode, String responseString, boolean isFile) throws Exception {

String statusLine = null;
String serverdetails = "Server: Java HTTPServer";
String contentLengthLine = null;
String fileName = null;
String contentTypeLine = "Content-Type: text/html" + "\r\n";
FileInputStream fin = null;

if (statusCode == 200)
statusLine = "HTTP/1.1 200 OK" + "\r\n";
else
statusLine = "HTTP/1.1 404 Not Found" + "\r\n";

if (isFile) {
fileName = responseString;
fin = new FileInputStream(fileName);
contentLengthLine = "Content-Length: " + Integer.toString(fin.available()) + "\r\n";
if (!fileName.endsWith(".htm") && !fileName.endsWith(".html"))
contentTypeLine = "Content-Type: \r\n";
}
else {
responseString = myHTTPServer.HTML_START + responseString + myHTTPServer.HTML_END;
contentLengthLine = "Content-Length: " + responseString.length() + "\r\n";
}

outToClient.writeBytes(statusLine);
outToClient.writeBytes(serverdetails);
outToClient.writeBytes(contentTypeLine);
outToClient.writeBytes(contentLengthLine);
outToClient.writeBytes("Connection: close\r\n");
outToClient.writeBytes("\r\n");

if (isFile) sendFile(fin, outToClient);
else outToClient.writeBytes(responseString);

outToClient.close();
}

public void sendFile (FileInputStream fin, DataOutputStream out) throws Exception {
byte[] buffer = new byte[1024] ;
int bytesRead;

while ((bytesRead = fin.read(buffer)) != -1 ) {
out.write(buffer, 0, bytesRead);
}
fin.close();
}

public static void main (String args[]) throws Exception {

ServerSocket Server = new ServerSocket (5000, 10, InetAddress.getByName("127.0.0.1"));
System.out.println ("TCPServer Waiting for client on port 5000");

while(true) {
Socket connected = Server.accept();
    (new myHTTPServer(connected)).start();
}
}
}

享受吧!


我已经在关闭防火墙的情况下尝试在Chrome和Firefox中运行它。大约15次中只有一次在Chrome中成功了。我不明白出了什么问题。 - ALR
尝试在你的代码周围加上while(true)。也许你的应用程序关闭是因为多个请求正在被执行。 - Menelaos
@MenelaosBakopoulos 网站无法正常工作,看起来像是恶意软件,请更改或删除。 - thestephenstanton
1
@THE Stephen Stanton 我已经更新了链接,从互联网档案馆中读取。同时也包含了原始源代码的副本。 - Menelaos

1

你需要接受客户端(在这种情况下是浏览器)发送的请求,只需添加以下行:

Buffered reader in = new Buffered reader(new InputStreamReader(client_socket.getInputStream()));

注意:您需要将“client_socket”部分替换为客户端自己的套接字名称。
为什么我们需要接受浏览器请求? 这是因为如果我们不接受请求,浏览器就无法从服务器获得任何确认,表明已收到发送的请求,因此它认为服务器不再可达。
我的代码:
public class Help {
    public static void main(String args) throws IOException{
        ServerSocket servsock new serverSocket(80)
        Socket cs servsock, accept();
        Printwriter out new Printwriter(Cs.getoutputstream), true)
        BufferedReader in new BufferedReader(new InputStreamReader(cs.getInputStream());
        out.println("<html> <body> <p>My first StackOverflow answer </p> </body> </html>");
        out.close();
        servsock.close();
    }
}

1
  1. HTTP中的行终止符是\r\n.这意味着您不应使用println(),而应该使用print()并自己添加明确的\r\n到每行。

  2. HTTP GET的结果应该是HTML文档,而不是片段。浏览器有权忽略或抱怨。发送以下内容:

    <html>
    <head/>
    <body>
    <p> 你好世界 </p>
    </body>
    </html>
    

1
你需要在打印时将PrintWriter设置为自动刷新。 PrintWriter out = new PrintWriter(clientSocket.getOutputStream()); 应该改为 PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);

1
在我的电脑上,至少需要获取套接字的输入流:
clientSocket.getInputStream();

没有这一行,有时Chrome无法工作。

你需要先从套接字中读取输入。

BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String line = "";
while((line = bufferedReader.readLine()) != null){
    System.out.println(line);
    if(line.isEmpty())
        break;
}


对于其他遇到类似问题的人,你不需要读取输入,但是如果你这样做,请确保你的代码不会在读取时卡住(我的代码就是)。当我切换到上面的代码并使用BufferedReaderreadLine时,它就可以工作了,但readAllBytes不起作用。 - dtasev

0
你需要先发送 "HTTP/1.1 200 OK",然后换行, 接着发送 "Content-Type: text/html; charset: UTF-8",再加上两个换行符。 最后发送 HTML 源代码以显示为样式化的网页而不仅仅是文本输出。
我使用了 OutputStreamWriter。
OutputStreamWriter osw = new OutputStreamWriter(socket.getOutputStream());

osw.write("HTTP/1.1 200 OK\nContent-Type: text/html; charset=UTF-8\n\n");
osw.write("<html><head><title>Hello World</title></head><body></body><p>Hello World</p></body></html>");

如果不先发送“HTTP/1.1 200 OK”,则源代码将被显示而没有进行HTML解析。

为了避免“连接被重置”错误,您需要关闭套接字。非常重要!

整个代码:

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class WebServer
{
    ServerSocket serverSocket;
    Socket socket;

    FileReader fr;
    OutputStreamWriter osw;

    WebServer() throws IOException
    {
        serverSocket = new ServerSocket(8080);
        socket = serverSocket.accept();

        fr = new FileReader("index.html");
        osw = new OutputStreamWriter(socket.getOutputStream());

        osw.write("HTTP/1.1 200 OK\nContent-Type: text/html; charset=UTF-8\n\n");

        int c;
        char[] ch = new char[4096];
        while ((c = fr.read(ch)) != -1)
        {
            osw.write(ch, 0, c);
        }

        osw.close();
        socket.close();
    }

    public static void main(String[] args) throws IOException
    {
        new WebServer();
    }
}

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