Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 服务线程中的循环不';在客户端关闭套接字后不会中断_Java_Multithreading_Sockets - Fatal编程技术网

Java 服务线程中的循环不';在客户端关闭套接字后不会中断

Java 服务线程中的循环不';在客户端关闭套接字后不会中断,java,multithreading,sockets,Java,Multithreading,Sockets,我是初学者,正在学习socket编程,并试图用Java实现简单的类似Sinatra的库。 while循环取决于客户端套接字是否关闭(!this.client.isClosed()),到目前为止,工作只响应最小的请求,如“GET/HTTP/1.1”,直到客户端关闭连接,while循环进入无限循环并占用所有cpu周期,我还尝试添加附加条件检查客户端的可用性InputStream是否返回-1(这意味着已关闭?),而(!this.client.isClosed()&&&(reader.available

我是初学者,正在学习socket编程,并试图用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
使用ant运行并从浏览器发出测试请求,记录:

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] =============
关闭选项卡或断开与客户端的连接后,它进入有限循环,尽管客户端套接字已关闭,(!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] =============
  • 您的循环条件不正确
    Socket.isClosed()
    仅告诉您是否已关闭套接字。要检测近邻,您必须检查正在使用的任何读取方法的返回值:

    • read()
      返回-1
    • readLine()
      返回
      null
    • readObject()
      和所有其他
      readXXX()
      方法抛出
      EOFEException.
    当你得到任何这些你必须关闭插座和保释

  • 毫无疑问,您在写操作中得到了
    IOException:connection reset
    ,但当您忽略所有
    IOExceptions
    时,您没有看到它们。永远不要忽略
    IOExceptions
    。只有一种对连接不是致命的,那就是读取时的
    SocketTimeoutException
    。当你得到任何其他你必须关闭插座和保释

  • 测试
    (in.available()!=-1)
    完全没有意义。它永远不会返回-1,并且它不会返回任何指示流结束的内容


  • 谢谢@EJP,解决了,我添加了helper方法来检查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()){
        ...
    }
    

    你不需要这些。在正常流程中遇到EOS时,您只需正确地对EOS作出反应。