2014-11-25 68 views
0

我是初学者学习套接字编程并试图在Java中实现简单的Sinatra类库。 while循环以客户端套接字为关闭或不((!this.client.isClosed())),到目前为止,它是工作响应最小的请求,如“GET/HTTP/1.1”,直到客户端关闭连接,while循环去无限循环,并采取所有的CPU周期,我也试图添加额外的条件检查可用性客户端的InputStream返回-1(意思是关闭?),而(!this.client.isClosed()& &(reader.available( )!= -1))。循环服务线程在客户端关闭套接字后不会中断

WebServer.java

public void start(){ 
    try{ 
     while(true){ 
      // accept and add incoming socket connection to client bulks 
      this.clients.put(++requestNumber, this.server.accept()); 
      // service client request in Service thread 
      Service service = new Service(this); 
      service.start(); 
     } 
    } 
    catch(IOException ioe){ 
     System.out.println(ioe.getMessage()); 
    } 
    finally{ 
     // TODO: close server socket here 
    } 
}// end start 

Service.java

@Override 
public void run(){ 
    while(!this.client.isClosed()){ 
     System.out.println("read request"); 

     // parse http request 
     this.parser.parse(); 
     String method = this.parser.getMethod(); 
     String path = this.parser.getPath(); 
     String httpVer = this.parser.getHttpVersion(); 
     System.out.println("[METHOD] : "+method); 
     System.out.println("[PATH] : "+path); 
     System.out.println("[HTTP VERSION] : "+httpVer); 

     // match request with specified handler in handlers bulk 
     for(RequestHandler handler:this.server.handlers){ 
      if(handler.getMethod().equals(method)){ 
       if(handler.getPath().equals(path)){ 
        System.out.println("send response\n============="); 
        // serve request 
        handler.handle(this.reader, this.writer); 
       } 
      } 
     }// end for loop 

     // debug only 
     try{Thread.currentThread().sleep(3000);}catch(InterruptedException ie){} 

    }// end while loop 

    // not get executed after client disconnect 
    System.out.println("exit service thread"); 
    // remove client socket in client sockets bulk 
    server.clients.remove(requestId); 

}// end run 

HttpParser.java

// start HttpParser 
public class HttpParser{ 
    private BufferedInputStream in; 
    private String initial; 
    private String header; 

    public HttpParser(BufferedInputStream in){ 
     this.in = in; 
    } 

    public void parse(){ 
     System.out.println("parse request"); 
     // pattern to match both \r\n or \n 
     Pattern pattern = Pattern.compile("\r?\n", Pattern.DOTALL); 
     Matcher match = null; 
     Scanner scanner = null; 
     StringBuilder requestBuffer = new StringBuilder(""); 
     String request = ""; 
     int nread = 0, nlength = 0; 
     try{ 
      scanner = new Scanner(in).useDelimiter(pattern); 
      while((in.available() != -1) && scanner.hasNext()){ 
       // read line from request 
       String line = scanner.next(); 

       // break while loop if find empty line "\r\n\r\n" or "\n\n" 
       if(line.isEmpty()){break;} 

       // append line to buffer 
       requestBuffer.append(line+"\r\n"); 
      } 

      // get full request from buffer 
      request = requestBuffer.toString(); 
      System.out.println("[REQUEST]\n"+request); 

      // get initial header from request 
      match = Pattern.compile("^.*?\r\n").matcher(request); 
      if(match.find()){ 
       // assign initial header to initial member 
       this.initial = match.group(); 
       System.out.println("[INITIAL HEADER]\n"+this.initial); 
      } 
     } 
     catch(IOException ioe){} 
    }// end parse 

    // get method from initial header 
    public String getMethod(){ 
     Pattern pattern = Pattern.compile("(^.*?)\\s+"); 
     Matcher match = pattern.matcher(this.initial); 
     if(match.find()){ 
      return match.group(1); 
     } 
     return "GET"; 
    } 

    // get path from initial header 
    public String getPath(){ 
     Pattern pattern = Pattern.compile("^.*?\\s+(.+?)\\s+"); 
     Matcher match = pattern.matcher(this.initial); 
     if(match.find()){ 
      return match.group(1); 
     } 
     return "/"; 
    } 

    // get http version from initial header 
    public String getHttpVersion(){ 
     Pattern pattern = Pattern.compile("^.*?\\s+.+?\\s+HTTP/(\\d\\.\\d)\\s.*"); 
     Matcher match = pattern.matcher(this.initial); 
     if(match.find()){ 
      return match.group(1); 
     } 
     return "1.1"; 
    } 

} 
// end HttpParser 

主类Jciw.java

import java.io.*; 

// start Jciw 
public class Jciw{ 

    public static void main(String[] args){ 
     WebServer webServer = new WebServer(8000); 
     webServer.handle_request("GET", "/", new RootGetHandler()); 
     webServer.handle_request("POST", "/", new RootPostHandler()); 
     webServer.start(); 
    } 

    // start RootGetHandler 
    public static class RootGetHandler extends RequestHandler{ 
     @Override 
     public void handle(InputStream reader, OutputStream writer){ 
      try{ 
       writer.write(("Hello GET request\n").getBytes()); 
       writer.flush(); 
      } 
      catch(IOException ioe){ 

      } 
     } 
    } 
    // end RootGetHandler 

    // start RootPostHandler 
    public static class RootPostHandler extends RequestHandler{ 
     @Override 
     public void handle(InputStream reader, OutputStream writer){ 
      try{ 
       writer.write(("Hello POST request\n").getBytes()); 
       writer.flush(); 
      } 
      catch(IOException ioe){ 

      } 
     } 
    } 
    // end RootPostHandler 

} 
// end Jciw 

运行与浏览器蚂蚁,使测试请求,请登录:

run: 
[java] read request 
[java] parse request 
[java] [REQUEST] 
[java] GET/HTTP/1.1 
[java] Host: localhost:8000 
[java] User-Agent: Mozilla/5.0 (X11; Linux i686; rv:22.0) Gecko/20100101 Firefox/22.0 SeaMonkey/2.19 
[java] Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 
[java] Accept-Language: en-US,en;q=0.5 
[java] Accept-Encoding: gzip, deflate 
[java] Connection: keep-alive 
[java] 
[java] [INITIAL HEADER] 
[java] GET/HTTP/1.1 
[java] 
[java] [METHOD] : GET 
[java] [PATH] :/
[java] [HTTP VERSION] : 1.1 
[java] send response 
[java] ============= 

从客户端关闭标签或断开后它会inifinite循环althought客户端套接字已经关闭,而应该(this.client.isClosed()!)评估为false,服务线程永远不会退出,请登录:

[java] read request 
[java] parse request 
[java] [REQUEST] 
[java] 
[java] [METHOD] : GET 
[java] [PATH] :/
[java] [HTTP VERSION] : 1.1 
[java] send response 
[java] ============= 
[java] read request 
[java] parse request 
[java] [REQUEST] 
[java] 
[java] [METHOD] : GET 
[java] [PATH] :/
[java] [HTTP VERSION] : 1.1 
[java] send response 
[java] ============= 
[java] read request 
[java] parse request 
[java] [REQUEST] 
[java] 
[java] [METHOD] : GET 
[java] [PATH] :/
[java] [HTTP VERSION] : 1.1 
[java] send response 
[java] ============= 
[java] read request 
[java] parse request 
[java] [REQUEST] 
[java] 
[java] [METHOD] : GET 
[java] [PATH] :/
[java] [HTTP VERSION] : 1.1 
[java] send response 
[java] ============= 
[java] read request 
[java] parse request 
[java] [REQUEST] 
[java] 
[java] [METHOD] : GET 
[java] [PATH] :/
[java] [HTTP VERSION] : 1.1 
[java] send response 
[java] ============= 
[java] read request 
[java] parse request 
[java] [REQUEST] 
[java] 
[java] [METHOD] : GET 
[java] [PATH] :/
[java] [HTTP VERSION] : 1.1 
[java] send response 
[java] ============= 

回答

1
  1. 你的循环条件是不正确的。 Socket.isClosed()只告诉你是否已关闭插座。为了检测附近的同行,你必须检查任何读取方法,你正在使用的返回值:

    • read()返回-1
    • readLine()回报null
    • readObject()和所有其他readXXX()方法抛出EOFException.

    当你得到其中任何一个时,你必须关闭套接字并保释出来。

  2. 您无疑会在您的写入中获得IOException: connection reset,但由于您忽略了所有IOExceptions,因此您没有看到它们。永远不要忽视IOExceptions。只有一个不是致命的连接,那就是SocketTimeoutException。当你得到任何其他人时,你必须关闭插座并纾困。

  3. 测试(in.available() != -1)是完全没有意义的。它永远不会返回-1,并且它没有返回,表示流结束。

-1

感谢@EJP,解决了,我添加辅助方法来检查while循环的条件的客户端连接

private boolean isClosed(){ 
    int nread = 0; 
    try{ 
     this.reader.mark(1); 
     nread = this.reader.read(); 
     this.reader.reset(); 
    } 
    catch(IOException ioe){ 
     //TODO: when something goes wrong 
    } 
    return ((nread != -1)?false:true); 
} 
... 
while(!isClosed()){ 
    ... 
} 
+0

你不需要任何的。当你在正常流程中遇到它时,你只需要对EOS做出正确反应。 – EJP 2014-11-25 20:49:16

相关问题