-2

I'm implement a http server with version1.1 using java socket programming. I use a version 1.0 sample code and I want add the persistent connection feature by not closing socket utilt a "Connection : close" send to the server. However, I came accross with "java.net.SocketTimeoutException: Read timed out" info after an input like"localhost:8080/xxxx" on my browser and not receiving anything when tested with a client program. Code is too long, and I mention the matter parts bellow! Can you find the problems for me, thanks!!!

////////here is the server part using thread pool techs
//Webserver class
 protected static Properties props = new Properties();
/* Where worker threads stand idle */
static Vector threads = new Vector();
 public static void main(String[] a) throws Exception {
        int port = 8080;
        if (a.length > 0) {
            port = Integer.parseInt(a[0]);
        }
        loadProps();
        printProps();
        /* start worker threads */
        for (int i = 0; i < workers; ++i) {
            Worker w = new Worker();
            (new Thread(w, "worker #"+i)).start();
            threads.addElement(w);
        }
        ServerSocket ss = new ServerSocket(port);
        while (true) {
            Socket s = ss.accept();
            Worker w = null;
            synchronized (threads) {
                if (threads.isEmpty()) {
                    Worker ws = new Worker();
                    ws.setSocket(s);
                    (new Thread(ws, "additional worker")).start();
                } else {
                    w = (Worker) threads.elementAt(0);
                    threads.removeElementAt(0);
                    w.setSocket(s);
                }
            }
       }
}

//Worker class inherit from Webserver class
    byte[] buf;
    Worker() {
        buf = new byte[BUF_SIZE];
        s = null;
    }

    synchronized void setSocket(Socket s) {
        this.s = s;
        notify();
    }

    public synchronized void run() {
        while(true) {
            if (s == null) {
                /* nothing to do */
                try {
                    wait();
                } catch (InterruptedException e) {
                    /* should not happen */
                    continue;
                }
            }
            try {
                handleClient();
            } catch (Exception e) {
                e.printStackTrace();
            }
            /* go back in wait queue if there's fewer
             * than numHandler connections.
             */
            if(!headAttri.getPersistConnec())
                s = null;
            //
            Vector pool = WebServer.threads;
            synchronized (pool) {
                if (pool.size() >= WebServer.workers) {
                    /* too many threads, exit this one */
                    try{
                        if(s != null)
                            s.close();
                    }catch (IOException e) {
                        e.printStackTrace();
                    }
                    return;
                } else {
                    if(!headAttri.getPersistConnec())
                        pool.addElement(this);
                }
            } 
        }
    }

//in handle client I mention the socket handles here(s is the socket)
void handleClient() throws IOException {
//...
s.setSoTimeout(WebServer.timeout);
s.setTcpNoDelay(true);

//...
try{
//...handle request and response the client
//...
}finally{
//close socket if head info "Connection: close" is found
            if(headAttri.getPersistConnec()){
                s.setKeepAlive(true);
            }
            else{
                s.close();
            }

}

}
//////////end server part

//////here is the client part
public SimpleSocketClient()
  {
    String testServerName = "localhost";
    int port = 8080;
    try
    {
      // open a socket
      Socket socket = openSocket(testServerName, port);

      // write-to, and read-from the socket.
      // in this case just write a simple command to a web server.
      String result = writeToAndReadFromSocket(socket, request_str[1]);

      // print out the result we got back from the server
      System.out.println(result);

      // close the socket, and we're done
      socket.close();
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }
  }

private Socket openSocket(String server, int port) throws Exception
  {
    Socket socket;

    // create a socket with a timeout
    try
    {
      InetAddress inteAddress = InetAddress.getByName(server);
      SocketAddress socketAddress = new InetSocketAddress(inteAddress, port);

      // create a socket
      socket = new Socket();

      // this method will block no more than timeout ms.
      int timeoutInMs = 10*1000;   // 10 seconds
      socket.connect(socketAddress, timeoutInMs);

      return socket;
    } 
    catch (SocketTimeoutException ste) 
    {
      System.err.println("Timed out waiting for the socket.");
      ste.printStackTrace();
      throw ste;
    }
  }

private String writeToAndReadFromSocket(Socket socket, String writeTo) throws Exception
  {
    try 
    {
      // write text to the socket
      BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
      bufferedWriter.write(writeTo);
      bufferedWriter.flush();
      //test
      //bufferedWriter.write("GET src/WebServer.java HTTP/1.1\r\nHost: localhost\r\nConnection: close");
      //bufferedWriter.flush();

      // read text from the socket
      BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
      StringBuilder sb = new StringBuilder();

      //string handling code
      String str;
      while ((str = bufferedReader.readLine()) != null)
      {
        sb.append(str + "\n");
      }

      // close the reader, and return the results as a String
      bufferedReader.close();
      return sb.toString();
    } 
    catch (IOException e) 
    {
      e.printStackTrace();
      throw e;
    }
  }
////end client part
stackKKK
  • 25
  • 1
  • 7
  • 2
    Welcome to StackOverflow. Please take some time to visit the [help] and also read [ask]. Questions of the form "here's my code, please debug it" are considered off-topic. StackOverflow is not a discussion, tutorial or debugging site. The way this works is you are expected to attempt to solve the problem and then ask for help when you run into a difficulty, explaining clearly what you have tried and what you don't understand. At a minimum you should already have stepped through the code in an IDE debugger and be able to identify results that don't match your expectation. – Jim Garrison Oct 13 '16 at 05:58

2 Answers2

1
//close socket if head info "Connection: close" is found
            if(headAttri.getPersistConnec()){
                s.setKeepAlive(true);

It is hard to tell from your code what you are really doing but based on this code fragment it looks like you are mixing up HTTP keep alive (i.e. Connection: keep-alive handling, multiple requests in a single TCP connection) with TCP keep alive (detect broken TCP connection). See Relation between HTTP Keep Alive duration and TCP timeout duration and HTTP Keep Alive and TCP keep alive for explanations about the difference.

Community
  • 1
  • 1
Steffen Ullrich
  • 114,247
  • 10
  • 131
  • 172
0

I want add the persistent connection feature by not closing socket utilt a "Connection : close" send to the server

That's not how you do it. You have to close the connection yourself, either

  • after a request with a Connection: close header is received and you've sent the response, or

  • when you get a read timeout on the socket reading the next request.

    The length of the read timeout is entirely up to you, because it is up to you to protect yourself from DOS attacks among other things.

NB calling Socket.setKeepAlive(true) has absolutely nothing whatsoever to do with it.

NB 2 You should look into java.util.concurrent.Executor rather than implement your own thread pool.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • If I select the first choice, there may be many requests already, so there may be many responses left to be sent. You mean that I send the responses util a request contains "Connection: close" header found or omit the requests with keep-alive but response the one with "Connection: close" only? But this is not the "a request a response" mode with HTTP, or I don't realize ? – stackKKK Oct 13 '16 at 15:19
  • You don't appear to understand. If you receive a request with `Connection: close` it is, by definition, the last request in the connection. Ergo its response is the final response. Ergo you can close the connection after sending it. – user207421 Oct 13 '16 at 23:24
  • @stackKKK You have to close one of those three to close the connection. You don't have to close them all. – user207421 Oct 16 '16 at 01:18