HTML代码无效 - socket - java

时间:2015-05-13 15:27:04

标签: java html sockets serversocket

我写的FileServermain()应该在给定的URL中写一条消息。但是当我把URL放在浏览器上时 - 应该写下这条消息:

<!DOCTYPE html>
<html>
<body>Yahoo! Your test was successful! <a href="/exit">Click here to exit</a></body>
</html>

而是写了消息但不是html。 希望你能帮助找出问题所在。

以下是3个类:HelloServerHelloClientFileServer

package net;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.List;

import javax.swing.text.html.HTMLDocument.Iterator;

public class HelloServer {

    private ServerSocket newOne;

    public static final String ERR_MESSAGE = "IO Error!";
    public static final String LISTEN_MESSAGE = "Listening on port: ";
    public static final String HELLO_MESSAGE = "hello ";
    public static final String BYE_MESSAGE = "bye"; 


    public ServerSocket getServerSocket() {
        return newOne;
    }

    /**
     * Listen on the first available port in a given list.
     * 
     * <p>Note: Should not throw exceptions due to ports being unavailable</p> 
     *  
     * @return The port number chosen, or -1 if none of the ports were available.
     *   
     */
    public int listen(List<Integer> portList) throws IOException {
        // change to for each
        Socket clientSocket = null;
        java.util.Iterator<Integer> iterator = portList.iterator();
        while(iterator.hasNext()){
            try{
                newOne = new ServerSocket(portList.get(iterator.next()));
                clientSocket = newOne.accept();
                if (clientSocket != null){
                    return getServerSocket().getLocalPort();        
                }
            }catch(IOException e){
                continue;
            }
        }
        return -1;  
    }


    /**
     * Listen on an available port. 
     * Any available port may be chosen.
     * @return The port number chosen.
     */
    public int listen() throws IOException {
        newOne = new ServerSocket(0);
        return newOne.getLocalPort();
    }


    /**
     * 1. Start listening on an open port. Write {@link #LISTEN_MESSAGE} followed by the port number (and a newline) to sysout.
     *    If there's an IOException at this stage, exit the method.
     * 
     * 2. Run in a loop; 
     * in each iteration of the loop, wait for a client to connect,
     * then read a line of text from the client. If the text is {@link #BYE_MESSAGE}, 
     * send {@link #BYE_MESSAGE} to the client and exit the loop. Otherwise, send {@link #HELLO_MESSAGE} 
     * to the client, followed by the string sent by the client (and a newline)
     * After sending the hello message, close the client connection and wait for the next client to connect.
     * 
     * If there's an IOException while in the loop, or if the client closes the connection before sending a line of text,
     * send the text {@link #ERR_MESSAGE} to sysout, but continue to the next iteration of the loop.
     * 
     * *: in any case, before exiting the method you must close the server socket. 
     *  
     * @param sysout a {@link PrintStream} to which the console messages are sent.
     * 
     * 
     */
    public void run(PrintStream sysout) {
        try{
            this.listen();
            sysout.print(LISTEN_MESSAGE + " " + newOne.getLocalPort() + "\n");
        }catch(IOException e){
            try {
                newOne.close();
            } catch (IOException e1) {
                System.out.println("can't close the socket");
            }
            System.exit(-1);
        }
        boolean legal = false;
        try{
            while(!legal){
                Socket clientSocket = newOne.accept();
                BufferedReader input = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
                PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
                String a = input.readLine();
                if (a.equalsIgnoreCase(BYE_MESSAGE)){   
                    out.print(BYE_MESSAGE);
                    legal = true;;
                }else{
                    out.print(HELLO_MESSAGE + a + "/n");
                    clientSocket.close();
                }
                newOne.close();
                out.close();
                input.close();
            }
            // move close to here and close the reader
        }catch(IOException e){
            sysout.println(ERR_MESSAGE);
        }
    }


    public static void main(String args[]) {
        HelloServer server = new HelloServer();

        server.run(System.err);
    }

}


package net;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.net.Socket;

import jdk.nashorn.internal.ir.CatchNode;

public class HelloClient {

    Socket clientSocket;

    public static final int COUNT = 10;

    /**
     * Connect to a remote host using TCP/IP and set {@link #clientSocket} to be the
     * resulting socket object.
     * 
     * @param host remote host to connect to.
     * @param port remote port to connect to.
     * @throws IOException
     */
    public void connect(String host, int port) throws IOException {
        clientSocket = new Socket(host, port);
    }

    /**
     * Perform the following actions {@link #COUNT} times in a row: 1. Connect
     * to the remote server (host:port). 2. Write the string in myname (followed
     * by newline) to the server 3. Read one line of response from the server,
     * write it to sysout (without the trailing newline) 4. Close the socket.
     * 
     * Then do the following (only once): 1. send
     * {@link HelloServer#BYE_MESSAGE} to the server (followed by newline). 2.
     * Read one line of response from the server, write it to sysout (without
     * the trailing newline)
     * 
     * If there are any IO Errors during the execution, output {@link HelloServer#ERR_MESSAGE}
     * (followed by newline) to sysout. If the error is inside the loop,
     * continue to the next iteration of the loop. Otherwise exit the method.
     * 
     * @param sysout
     * @param host
     * @param port
     * @param myname
     */
    public void run(PrintStream sysout, String host, int port, String myname) {
        try{
            int index = 0;
            boolean legal = false;
            PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
            BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
            while(!legal){
                if (index < COUNT){
                    try {
                        connect(host, port);
                        out.print(myname + "/n");
                        sysout.print(in.readLine());
                        clientSocket.close();
                    }catch(IOException e){
                        continue;   
                    }
                }else{
                    legal = true;
                }
            }
            out.print(HelloServer.BYE_MESSAGE + "/n");
            sysout.print(in.readLine());
        }catch(IOException e1){
            sysout.print(HelloServer.ERR_MESSAGE + "/n");
            System.exit(-1);        
        }
    }
}


package net;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class FileServer {

    static final String RESP_OK = "HTTP/1.0 200 OK\r\nConnection: close\r\n\r\n";
    static final String RESP_BADPATH = "HTTP/1.0 403 Forbidden\r\nConnection: close\r\n\r\nForbidden: ";
    static final String RESP_NOTFOUND = "HTTP/1.0 404 Not Found\r\nConnection: close\r\n\r\nNot found: ";
    static final String RESP_BADMETHOD = "HTTP/1.0 405 Method not allowed\r\nConnection: close\r\nAllow: GET\r\n\r\nBad";
    static final String RESP_EXIT = RESP_OK + "Thanks, I'm done.";

    static final String MSG_IOERROR = "There was an IO Error";
    static final String PATH_EXIT = "/exit";

    /**
     * Check if a string is a well-formed absolute path in the filesystem. A well-formed
     * absolute path must satisfy:
     * <ul>
     * <li>Begins with "/"
     * <li>Consists only of English letters, numbers, and the special characters
     * '_', '.', '-', '~' and '/'.
     * <li>Does not contain any occurrences of the string "/../".
     * </ul>
     * 
     * @param path
     *            The path to check.
     * @return true if the path is well-formed, false otherwise.
     */
    public boolean isLegalAbsolutePath(String path) {
        if ((path.charAt(0) != '/') && (!path.contains("/.../"))) {
            // check - not sure if it is working
            if (path.matches("[^-._~/A-Za-z]")){
            return false;   
            }
        }
        return true;
    }


    /**
     * This method should do the following things, given an open (already
     * listening) server socket:
     * <ol>
     *  <li>Do the following in a loop (this is the "main loop"):
     *  <ol>
     *      <li>Wait for a client to connect. When a client connects, read one line
     *      of input (hint: you may use {@link BufferedReader#readLine()} to read a
     *      line).
     *      <li>The client's first line of input should consist of at least two words
     *      separated by spaces (any number of spaces is ok). If it's less than two words,
     *      you may handle it in any reasonable way (e.g., just close the connection).
     *      <ul>
     *          <li>if the first word is not GET (case-insensitive), send the string
     *          {@link #RESP_BADMETHOD} to the client and close the connection.
     *          <li>otherwise, parse the second word as a full path (a filename,
     *          including directories, separated by '/' characters).
     *          <li>if the pathname is exactly {@value #PATH_EXIT} (case sensitive), send
     *          {@link #RESP_EXIT} to the client and close the connection. Then exit the
     *          main loop (do not close the server socket).
     *          <li>if the path is not a legal absolute path (use
     *          {@link #isLegalAbsolutePath(String)} to check) send
     *          {@link #RESP_BADPATH}, followed by the path itself, to the client and close the connection.
     *          <li>if the path is a legal path but the file does not exist or cannot be read,  
     *          {@link #RESP_NOTFOUND}, followed by the path itself, to the client and close the connection.
     *          <li>otherwise, send {@link #RESP_OK} to the client, then open the file
     *          and send its contents to the client. Finally, close the connection.
     *      </ul>
     *      <li>If there is an I/O error during communication with the client or
     *      reading from the file, output the string {@value #MSG_IOERROR} to sysErr
     *      and close the connection (ignore errors during close).
     *  </ol>
     * </ol>
     * 
     * @param serverSock
     *            the {@link ServerSocket} on which to accept connections.
     * @param sysErr
     *            the {@link PrintStream} to which error messages are written.
     */
    public void runSingleClient(ServerSocket serverSock, PrintStream sysErr) {
        Socket clientSocket = null;
        BufferedReader input = null;
        PrintWriter out = null;
        boolean legal = false;
        while (!legal){
            try{
                clientSocket = serverSock.accept();
                input = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
                out = new PrintWriter(clientSocket.getOutputStream(), true);
                String current = input.readLine();
                String[] clientResponse = ignoreWhiteSpace(current);
                if(clientResponse == null){
                    clientSocket.close();
                    System.exit(-1);
                }else if(!clientResponse[0].equalsIgnoreCase("get")){
                    out.print(RESP_BADPATH);
                    clientSocket.close();
                    input.close();
                    out.flush();

                }else{
                    String pathName = clientResponse[1];
                    //Path path = Paths.get(pathName);
                    if (pathName.equals(PATH_EXIT)){
                        out.println(RESP_EXIT);
                        clientSocket.close();
                        input.close();
                        out.flush();
                        legal = true;
                    }
                    if(!isLegalAbsolutePath(pathName)){
                        out.println(RESP_BADPATH + pathName);
                        clientSocket.close();
                        input.close();
                        out.flush();
                        legal = true;
                    }
                    File file = new File(pathName);
                    //}else if((!Files.exists(path)) || (!Files.isReadable(path))){
                    if(!file.exists() || !file.canRead()){
                        out.println(RESP_NOTFOUND + pathName);
                        clientSocket.close();
                        input.close();
                        out.flush();
                        legal = true;
                    }else{
                        out.println(RESP_OK);
                        //sendFileContentToClient(clientSocket.getOutputStream(), pathName);
                        String textFile = new String(Files.readAllBytes(Paths.get(pathName)));
                        out.println(textFile);
                        clientSocket.close();
                        input.close();
                        out.flush();
                        legal = true;
                    }                       
                }   
            }catch(IOException e){
                sysErr.print("There was an IO Error");  
            }
        }

    }

    /**
     * Convert a windows-style path (e.g. "C:\dir\dir2") to POSIX style (e.g. "/dir1/dir2")
     */
    static String convertWindowsToPOSIX(String path) {
        return path.replaceFirst("^[a-zA-Z]:", "").replaceAll("\\\\", "/");
    }

//  //private void sendFileContentToClient(OutputStream outputStream, String path)
//  //      throws IOException {
//  //  // Initialize buffer read and write/
//  //  BufferedReader in = new BufferedReader(new FileReader(path));
//      BufferedWriter out = new BufferedWriter(new PrintWriter(outputStream,
//              true));
//
//      // Read the file and write to the output stream.
//      long c = 0L;
//      while ((c = in.read()) != -1) {
//          out.write((int) c);
//      }
//
//      out.flush();
//      in.close();
//  }


    // add java doc and add check if the string is null
    private static String[] ignoreWhiteSpace(String a){
        if (a == null){
            return null;
        }
        int index = 0;
        String first = "";
        String second = "";
        String[] ignoreWhiteSpace = new String[2];
        while ((a.charAt(index) != ' ') && (index < a.length())){
            first = first + a.charAt(index);
            index++;
        }
        while((a.charAt(index) == ' ')){
            index++;
        }
        while((index < a.length())){
            if ((a.charAt(index) != ' ')){
            second = second + a.charAt(index);
            index++;
            }else{
                break;
            }
        }
        ignoreWhiteSpace[0] = first;
        ignoreWhiteSpace[1] = second;

        if((ignoreWhiteSpace[0].equals("")) || (ignoreWhiteSpace[1].equals(""))){
            return null;
        }else{
            return ignoreWhiteSpace;
        }
    }   

    /**
     * This is for your own testing.
     * If you wrote the code correctly and run the program,
     * you should be able to enter the "test URL" printed
     * on the console in a browser, see  a "Yahoo!..." message, 
     * and click on a link to exit.  
     * @param args
     */
    static public void main(String[] args){
        FileServer fs = new FileServer();

        HelloServer serve = new HelloServer();

        File tmpFile = null;
        try {
            try {
                tmpFile = File.createTempFile("test", ".html");
                FileOutputStream fos = new FileOutputStream(tmpFile);
                PrintStream out = new PrintStream(fos);
                out.println("<!DOCTYPE html>\n<html>\n<body>Yahoo! Your test was successful! <a href=\""+ PATH_EXIT +"\">Click here to exit</a></body>\n</html>");
                out.close();

                int port = serve.listen();
                System.err.println("Test URL: http://localhost:" + port
                        + convertWindowsToPOSIX(tmpFile.getAbsolutePath()));
            } catch (IOException e) {
                System.err.println("Exception, exiting: " + e);
                return;
            }

            fs.runSingleClient(serve.getServerSocket(), System.err);
            System.err.println("Exiting due to client request");

            try {
                serve.getServerSocket().close();
            } catch (IOException e) {
                System.err.println("Exception closing server socket, ignoring:"
                        + e);
            }
        } finally {
            if (tmpFile != null)
                tmpFile.delete();
        }
    }

}

0 个答案:

没有答案