我写的FileServer
类main()
应该在给定的URL中写一条消息。但是当我把URL放在浏览器上时 - 应该写下这条消息:
<!DOCTYPE html>
<html>
<body>Yahoo! Your test was successful! <a href="/exit">Click here to exit</a></body>
</html>
而是写了消息但不是html。 希望你能帮助找出问题所在。
以下是3个类:HelloServer
,HelloClient
和FileServer
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();
}
}
}