2011-06-28 11 views
2

キープアライブ接続を提供できる、HTTPでHTTPサーバーを作成しようとしています。私はcom.sun.net.httpserver.HttpServerクラスを使用しています。キープアライブ可能なHTTPサーバー

import java.io.IOException; 
import java.io.OutputStream; 
import java.net.InetSocketAddress; 

import com.sun.net.httpserver.Headers; 
import com.sun.net.httpserver.HttpExchange; 
import com.sun.net.httpserver.HttpHandler; 
import com.sun.net.httpserver.HttpServer; 

public class httpHandler implements HttpHandler { 

private String resp = "<?xml version='1.0'?><root-node></root-node>"; 

private OutputStream os = null; 

public void handle(HttpExchange t) throws IOException { 
    System.out.println("Handling message..."); 
    java.io.InputStream is = t.getRequestBody(); 

    System.out.println("Got request body. Reading request body..."); 
    byte[] b = new byte[500]; 
    is.read(b); 
    System.out.println("This is the request: " + new String(b)); 

    String response = resp; 
    Headers header = t.getResponseHeaders(); 
    header.add("Connection", "Keep-Alive"); 
    header.add("Keep-Alive", "timeout=14 max=100"); 
    header.add("Content-Type", "application/soap+xml"); 
    t.sendResponseHeaders(200, response.length()); 

    if(os == null) { 
     os = t.getResponseBody(); 
    } 

    os.write(response.getBytes()); 

    System.out.println("Done with exchange. Closing connection"); 
    os.close(); 
} 

public static void main(String[] args) { 
    HttpServer server = null; 
    try { 
     server = HttpServer.create(new InetSocketAddress(8080), 5); 
    } catch (IOException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
    server.createContext("/", new httpHandler()); 
    server.setExecutor(null); // creates a default executor 
    System.out.println("Starting server..."); 
    server.start(); 
} 
} 

クライアントは接続を閉じません。交換が行われた直後に、サーバーが代わりに閉じているように見えます。私はos.close行を削除しようとしましたが、サーバーは2番目の要求に応答しません。しかし、どちらもそれを閉じることはありません。私はそれがサーバーオブジェクトでメインコードで何かをすることを伴う感情を持っていますが、何が分かりません。 Googleはそれほど盛り上がっていない。

誰でもここにアイデアがありますか?どんな助けでも大歓迎です。

+0

OTだが 'os'は確かにここのローカル変数でなければならない。さもなければスレッドセーフではない。 – EJP

答えて

0

キープアライブヘッダーを送信するのはクライアントです。そうした場合、HttpServerは接続を閉じません。あなたはそれについて何もする必要はありません。

+0

問題は、クライアントがキープアライブヘッダーを送信することですが、サーバーはデータを待つ代わりに、データ/パケットを受信するたびに接続を閉じます。 – Paul

+0

@Paulは私のテストにしたがっていません。私は、GET要求とこれらのキープアライブヘッダを送信したソケットクライアントを書きましたが、まだサーバからEOSを読み込んでいません。実際には、ヘッダーがなくても、HTTP/1.1を送信する限り、キープアライブが1.1のデフォルトであるため、HTTP/1.1を送信する限り、それは行います。 – EJP

+1

それでは、btwソケットクライアントコードを共有してもらえますか? – Paul

3

リクエストのすべてのデータが消えていないように見えます。 -1を返すまではis.read()を続けて閉じてから閉じてください。

リクエストを削除していないので、まだバイトが残っています。サーバーは単に次の要求に「ジャンプ」することはできません。ディスクのようなものではなく、テープのようなものです。サーバーは、次の要求に達する前に、現在の要求からすべてのデータを読み取って(廃棄しなければならない)

これを制限することなく、サーバーを攻撃するために使用できます。サーバーはデフォルトで64Kという上限までしか消費しないようにしようとします。おそらく、64Kを超えるリクエストを受信して​​いる可能性があります。

通常、ハンドラは最初に要求全体を読み取る必要があります。さもなければ、それはどのように要求を提供するかを知っていますか?

さらに深刻なことに、要求が最初に排水されないと、デッドロックが発生する可能性があります。クライアントは通常、単純です。要求を書き込んだ後、応答を読み取ります。すべての要求を読み取る前にサーバーが応答を書き込む場合、クライアントは依然として要求を書き込んでいる可能性があります。どちらもお互いに書いていますが、どちらも読書していません。バッファがいっぱいになると、デッドロック状態になり、両方とも書き込み時にブロックされます。 write()のタイムアウトはありません。

1

は、サーバがなぜあなたは以前がnullだった場合にのみ、ResponseBody OutputStreamを得るのですか

1

を返信させていただきますt.close()を呼び出そうか?

if(os == null) { 
    os = t.getResponseBody(); 
} 

前回のリクエストと同じであるかどうかわからないので、毎回OutputStreamを取得する方がよい場合があります。

関連する問題