

用Socket和ServerSocket這兩個類模擬監(jiān)聽80端口請求的WEB服務(wù)器
其實很簡單的,我搞了一晚上才搞定。。。。。。
說說為神馬吧,主要是InputStream的阻塞機制!
剛開始,我一次性讀取1024字節(jié),成功了。然后我又想到如果請求的字節(jié)數(shù)很長的話,只讀取一次肯定不行, 于是就用循環(huán)的方法使用read方法讀取Request輸入流的數(shù)據(jù)。
然后,悲劇的事情就發(fā)生了!!! read方法竟然阻塞了,然后找資料找了好久找不到有用的資料,
只看見有人說用java.nio包里面的新類可以實現(xiàn)。 我就想啊,我是學(xué)習(xí)的,面對問題怎么能逃避了???

于是繼續(xù)研究其中的算法和InputStream提供的各種方法。(我想其中不合理的代碼就不必貼了,認(rèn)真看我這篇文章的人應(yīng)該都能想到的)
最先啊,是看到j(luò)ava.nio.channel包里面有將InputStream轉(zhuǎn)換為可讀通道的方法,我就試了試,轉(zhuǎn)換之后,發(fā)現(xiàn)、、、無論算法怎么處理、讀取著還是不行啊。 仍然阻塞
然后,我想到一種方法:
???? 就是定義字節(jié)數(shù)組一定長度LEN, 然后循環(huán)讀取, 如果某一次讀取到的數(shù)據(jù)(read(buf)的返回值)小于100的話,不是意味著輸入流讀取到了結(jié)尾了么? 然后我就高高興興的實現(xiàn)這種想法了



又一次失敗了

我就繼續(xù)想啊想,就想到了InputStream提供的available()方法,這個方法返回的是下一次讀取的估計字節(jié)數(shù),當(dāng)初我就看到了這個方法,但是看到文檔上說的這個方法不建議使用,就一直沒想用。。。真是到了無可奈何啊。只好又試試這個方法的效果
于是呢,我就用了這種方法:
????? 在每一次循環(huán)讀取之前判斷InputStream剩余的字節(jié)數(shù)是不是 0 、即剩余字節(jié)是不是空的,如果是空的就不讀了,這種方法果然奏效!!! 但是經(jīng)過我的反復(fù)測試啊,發(fā)現(xiàn)又出現(xiàn)了一個問題,同一個瀏覽器的同一個頁面如果刷新的話,這個頁面第一次請求時候available() 正常, 下來的請求就不正常了,available()直接就 == 0 了, 第一次頁面請求 之后 的每一次頁面刷新后臺都讀取不到請求數(shù)據(jù)。 Socket我都關(guān)閉了啊!怎么會出現(xiàn)這種情況??? 納悶了, 又找了好長時間的資料,仍然沒有解決辦法。好像是上一次處理的InputStream的available()保留下來了一樣,但是如果另開一個頁面請求就正常。。。。



然后就是我想到的終極解決辦法了, 我假設(shè)的是 用戶請求內(nèi)容不可能是空值 ,于是,我就用了do{}while循環(huán),先執(zhí)行讀取一次,在判斷available()的值是不是0,這樣就保證了上一個問題的影響。 至于為什么這么做,我也是說不明白的,就是當(dāng)時的一種靈感吧。。。我感覺是為了把InputStream讀取指針先放在流頭。這樣可以避免干擾。






第一次發(fā)不會貼代碼、試試吧!
主服務(wù)類:
package server.test01; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; /** * @author sulin */ public class MyService { private final String HOST = "127.0.0.1"; //綁定的主機127.0.0.1,不設(shè)置也可、默認(rèn)即為IP或localhost private final int BACKLOG = 1; //最大請求并發(fā)量 private final int PORT = 80; //服務(wù)器綁定端口 public void startService(){ //建立指定HOST和PORT的服務(wù)器 ServerSocket server = null; try { server = new ServerSocket(this.PORT, this.BACKLOG, InetAddress.getByName(this.HOST)); } catch (IOException e) { e.printStackTrace(); } //服務(wù)開始工作 System.out.println("服務(wù)器開始工作"); while(true){ try{ //偵測一次請求 final Socket socket = server.accept(); final InputStream in = socket.getInputStream(); final OutputStream out = socket.getOutputStream(); //多線程機制響應(yīng)請求 new Thread(){ public void run() { try { //處理響應(yīng)偵探到的請求 MyRequest request = new MyRequest(in); request.Parse(); MyResponse response = new MyResponse(out); response.setRequest(request); response.SendResponse(); //本次請求處理結(jié)束 socket.close(); } catch (IOException e) { e.printStackTrace(); } } }.start(); }catch(Exception e){ e.printStackTrace(); } } } /** * 程序入口 * @param args */ public static void main(String[] args) { MyService service = new MyService(); service.startService(); } }
請求處理類
package server.test01; import java.io.IOException; import java.io.InputStream; public class MyRequest { private InputStream in; //請求的輸入流 private String uri; //請求的uri private String request = ""; //請求處理后的字符串 public MyRequest( InputStream in ) { this.in = in; } public String getUri() { return uri; } /** * 提供對request請求的解析服務(wù) */ public void Parse(){ try { byte[] buffer = new byte[377]; int len; do{ len = in.read(buffer); request += new String(buffer).substring(0, len); }while(in.available()>0); } catch (IOException e) { e.printStackTrace(); } this.uri = this.ParseURI(); System.out.println(uri); } private String ParseURI(){ String[] ss = this.request.trim().split(" "); if(ss.length > 2){ return ss[1]; }else{ return ""; } } }
另外一個相應(yīng)類MyResponse就不貼了。。。

更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
