我正準備在Java中進行編程練習,我希望我的學生能夠發現HTTP本身的內在特性,而不是讓URLConnection爲他們完成所有工作。爲了估計複雜性,我想出了以下片段,它解析了答覆(imho,工作中最難的部分之一),它將返回例如「HTTP/1.1 200 OK」,推之類「服務器:makato」和「內容長度:1337」中的頭矢量,並在內容的第一個字節離開的InputStream,這樣一個DataInputStream或InputStreamReader可以稍後安全地建立在它之上。通過Java套接字接收混合媒體。你更好嗎?
我很想知道是否有更多的Java類經驗的人可以提出更優雅的選擇。我不滿意的一件事是,每個人都是.read()將不可避免地生成一個額外的系統調用(假設Socket.getInputStream()用於餵養是參數)。
public static String recvHttpHeaders(InputStream is, Vector<String> headers)
throws Exception {
byte line[] = new byte[512];
String pending=null;
String status=null;
boolean complete=false, CR=false;
int n=0;
while (!complete) {
int x = is.read();
switch(x) {
case -1: throw new Exception("something went wrong");
case '\r':
if (CR) throw new Exception("encoding mismatch CRCR");
CR=true;
break;
case '\n': // bare LF are accepted silently.
String ln = new String(line,0,n,"ASCII");
if (pending!=null) ln = pending + ln;
if (status==null) status = ln;
else headers.add(ln);
complete = ln.length()==0;
pending = null;
n=0; CR=false;
break;
default:
if (CR) throw new Exception("encoding mismatch ?CR");
if (n>=512) {
String part = new String(line, "ASCII");
if (pending!=null) pending += part;
else pending = part;
n=0;
}
line[n++]=(byte)x;
break;
}
}
return status;
}
編輯:誠然,一個喜歡使用xxx.readline()這裏,以避免與線重建搞亂。 BufferedReader(或任何其他* Reader,實際上)根據一個字符集將字節轉換爲字符。這意味着如果我在頭文件解析中使用了該功能,則不再可以自由選擇該內容的字符集。我還沒有找到任何內置readline能力的字節級類。
性能解決方案:感謝您指出BufferedInputStream。我做了一些額外的測試,而事實上,作爲調用
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
String status = recvHttpHeaders(bis, headers);
rawCopy(bis, output);
確實減少執行系統調用的數量,還是讓我正確地接收二進制內容不變。
非常高興得到關於_conceiving_作業而不是解決問題的一個問題^^ – Dunaril 2011-03-01 17:07:56
爲了克服系統讀取每讀取問題,您可以通過BufferedInputStream封裝'socket.getInputStream()'。只要你爲標題和正文使用相同的'BufferedInputStream',你就不會有任何問題。 – 2011-03-01 19:06:59