AndroidではHttpGet#abort()が効かないみたいな疑惑
OpenJDKでもOracleJDKでも、org.apache.http.client.methods.HttpGetのexecute()でblockしている間, 以下のように別Threadからabort()させることができます。
public class App { public static void main(String args[]) { final String hostname = "localhost"; final HttpClient cli = new DefaultHttpClient(); final HttpHost host = new HttpHost(hostname, 8080); final HttpGet req = new HttpGet("http://" + hostname); Runnable task = new Runnable() { public void run() { HttpResponse res; try { res = cli.execute(host, req); System.out.println("StatusLine => " + res.getStatusLine()); } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { System.out.println("Finish"); } } }; ExecutorService es = Executors.newSingleThreadExecutor(); es.execute(task); try { Thread.sleep(5 * 1000); } catch (InterruptedException e) {} req.abort(); System.out.println("Abort"); try { Thread.sleep(5 * 1000); } catch (InterruptedException e) {} es.shutdown(); } }
netcatでlistenするだけにしておいて, Javaのプログラムを起動させると...
komamitsu@carrot:~$ netcat -l 8080 GET / HTTP/1.1 Host: localhost:8080 Connection: Keep-Alive User-Agent: Apache-HttpClient/4.1.2 (java 1.5)
以下のようなログを吐いて処理が終わる。
Abort Nov 4, 2011 1:23:05 AM org.apache.http.impl.client.DefaultRequestDirector tryExecute INFO: I/O exception (java.net.SocketException) caught when processing request: Socket closed Finish Nov 4, 2011 1:23:05 AM org.apache.http.impl.client.DefaultRequestDirector tryExecute INFO: Retrying request :
ところがこれと同等のことをAndroidでやろうとすると...
public class HttpAndroidActivity extends Activity { protected static final String TAG = HttpAndroidActivity.class.getSimpleName(); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); final String hostname = "10.0.2.2"; // Emulatorから見たHost PCのIP Address final HttpClient cli = new DefaultHttpClient(); final HttpHost host = new HttpHost(hostname, 8080); final HttpGet req = new HttpGet("http://" + hostname); Runnable task = new Runnable() { public void run() { HttpResponse res; try { res = cli.execute(host, req); Log.i(TAG, "StatusLine => " + res.getStatusLine()); } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { Log.i(TAG, "Finish"); } } }; ExecutorService es = Executors.newSingleThreadExecutor(); es.execute(task); try { Thread.sleep(5 * 1000); } catch (InterruptedException e) {} req.abort(); Log.i(TAG, "Abort"); es.shutdown(); } }
HTTPのRequestがきた後
komamitsu@carrot:~$ netcat -l 8080 GET / HTTP/1.1 Host: 10.0.2.2:8080 Connection: Keep-Alive User-Agent: Apache-HttpClient/UNAVAILABLE (java 1.4)
abort()されているのに、全然execute()が中断されない...
I/ActivityManager( 58): Starting activity: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.komamitsu/.HttpAndroidActivity } I/HttpAndroidActivity( 423): Abort I/ActivityManager( 58): Displayed activity com.komamitsu/.HttpAndroidActivity: 5165 ms (total 5165 ms)
これはDalvikのコードを見ていく必要がありそうな気がするなぁ。
追記 (2011-11-04 01:50) :
AndroidのほうはOS2.2で試して上記の現象を確認したのだけど、2.3.3上では正常に動作する...
I/HttpAndroidActivity( 319): Abort W/System.err( 319): java.net.SocketException: Socket closed W/System.err( 319): at org.apache.harmony.luni.platform.OSNetworkSystem.read(Native Method) W/System.err( 319): at dalvik.system.BlockGuard$WrappedNetworkSystem.read(BlockGuard.java:273) W/System.err( 319): at org.apache.harmony.luni.net.PlainSocketImpl.read(PlainSocketImpl.java:458) W/System.err( 319): at org.apache.harmony.luni.net.SocketInputStream.read(SocketInputStream.java:85) W/System.err( 319): at org.apache.http.impl.io.AbstractSessionInputBuffer.fillBuffer(AbstractSessionInputBuffer.java:103) W/System.err( 319): at org.apache.http.impl.io.AbstractSessionInputBuffer.readLine(AbstractSessionInputBuffer.java:191) W/System.err( 319): at org.apache.http.impl.conn.DefaultResponseParser.parseHead(DefaultResponseParser.java:82) W/System.err( 319): at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:174) W/System.err( 319): at org.apache.http.impl.AbstractHttpClientConnection.receiveResponseHeader(AbstractHttpClientConnection.java:179) W/System.err( 319): at org.apache.http.impl.conn.DefaultClientConnection.receiveResponseHeader(DefaultClientConnection.java:235) W/System.err( 319): at org.apache.http.impl.conn.AbstractClientConnAdapter.receiveResponseHeader(AbstractClientConnAdapter.java:259) W/System.err( 319): at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:279) W/System.err( 319): at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:121) W/System.err( 319): at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:421) W/System.err( 319): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555) W/System.err( 319): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:509) W/System.err( 319): at com.komamitsu.HttpAndroidActivity$1.run(HttpAndroidActivity.java:35) W/System.err( 319): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088) W/System.err( 319): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581) W/System.err( 319): at java.lang.Thread.run(Thread.java:1019) I/HttpAndroidActivity( 319): Finish I/ActivityManager( 61): Displayed com.komamitsu/.HttpAndroidActivity: +5s246ms