Socketに出力中に Connection reset by peer: socket write error

Javaでプロキシサーバのようなものを作っていたところ、クライアントへレスポンスを返している途中に、以下の例外が多発。


SocketException: Connection reset by peer: socket write error

プログラムはすごく簡単なサンプルを参考にしてたので間違ってるとは思えなかった。。。


String CrLf = "\r\n";

ServerSocket ss = new ServerSocket(9950);
Socket s = ss.accept();

StringBuffer b = new StringBuffer();
b.append("HTTP/1.1 200 OK" + CrLf);
b.append("Connection: close" + CrLf);
b.append("Date: Tue, 20 May 2008 18:02:41 GMT" + CrLf);
b.append("Content-Type: text/html;charset=UTF-8" + CrLf);
b.append("Transfer-Encoding: chunked" + CrLf);
b.append(CrLf);

OutputStream o = s.getOutputStream();
o.write(b.toString().getBytes());

InputStream contents = any....    ←なんらかのコンテンツ

for (int data = 0; (data = contents.read()) != -1; )
o.write(data);

o.flush();
o.close();
s.close();

が、うまく動いているサンプルと比べてみると「Transfer-Encoding: chunked」のところが違っている。うまく動いているサンプルは代わりに「Content-Length」ヘッダーがある。これは怪しそう、と思って調べてみたところ、以下のサイトに完璧な説明がありました。

http://www.cresc.co.jp/tech/java/Servlet_Tutorial/Att_01.htm

「Chunked Transfer-Encoding=厚切りエンコーディング」である、と。なるほど。以下のように修正したらバッチリ動きました。


String CrLf = "\r\n";

ServerSocket ss = new ServerSocket(9950);
Socket s = ss.accept();

StringBuffer b = new StringBuffer();
b.append("HTTP/1.1 200 OK" + CrLf);
b.append("Connection: close" + CrLf);
b.append("Date: Tue, 20 May 2008 18:02:41 GMT" + CrLf);
b.append("Content-Type: text/html;charset=UTF-8" + CrLf);
b.append("Transfer-Encoding: chunked" + CrLf);
b.append(CrLf);

OutputStream o = s.getOutputStream();
o.write(b.toString().getBytes());

InputStream contents = any....    ←なんらかのコンテンツ

byte[] bt = new byte[500];

for (int len = 0; (len = contents.read(bt, 0, 500)) != -1; ) {
o.write(Integer.toString(len, 16).getBytes()); ←←この部分を追加
o.write('\r');
o.write('\n');
o.write(data, 0, len);
}
o.write('0');

o.flush();
o.close();
s.close();