黄色网页视频 I 影音先锋日日狠狠久久 I 秋霞午夜毛片 I 秋霞一二三区 I 国产成人片无码视频 I 国产 精品 自在自线 I av免费观看网站 I 日本精品久久久久中文字幕5 I 91看视频 I 看全色黄大色黄女片18 I 精品不卡一区 I 亚洲最新精品 I 欧美 激情 在线 I 人妻少妇精品久久 I 国产99视频精品免费专区 I 欧美影院 I 欧美精品在欧美一区二区少妇 I av大片网站 I 国产精品黄色片 I 888久久 I 狠狠干最新 I 看看黄色一级片 I 黄色精品久久 I 三级av在线 I 69色综合 I 国产日韩欧美91 I 亚洲精品偷拍 I 激情小说亚洲图片 I 久久国产视频精品 I 国产综合精品一区二区三区 I 色婷婷国产 I 最新成人av在线 I 国产私拍精品 I 日韩成人影音 I 日日夜夜天天综合

WEB服務(wù)器工作機(jī)制由淺至深(1):多線程模擬服

系統(tǒng) 2016 0
?

用Socket和ServerSocket這兩個(gè)類模擬監(jiān)聽80端口請(qǐng)求的WEB服務(wù)器
其實(shí)很簡單的,我搞了一晚上才搞定。。。。。。

說說為神馬吧,主要是InputStream的阻塞機(jī)制!
剛開始,我一次性讀取1024字節(jié),成功了。然后我又想到如果請(qǐng)求的字節(jié)數(shù)很長的話,只讀取一次肯定不行, 于是就用循環(huán)的方法使用read方法讀取Request輸入流的數(shù)據(jù)。
然后,悲劇的事情就發(fā)生了!!! read方法竟然阻塞了,然后找資料找了好久找不到有用的資料,
只看見有人說用java.nio包里面的新類可以實(shí)現(xiàn)。 我就想啊,我是學(xué)習(xí)的,面對(duì)問題怎么能逃避了??? ?
于是繼續(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é)尾了么? 然后我就高高興興的實(shí)現(xiàn)這種想法了 ? ? 。 再然后呢。。。我就發(fā)現(xiàn)如果InputStream里面的字節(jié)數(shù)如果是LEN的整倍數(shù)的話,最后一次讀取也是 ==LEN的,還是會(huì)出現(xiàn) read方法已經(jīng)到了結(jié)尾但是循環(huán)仍然執(zhí)行導(dǎo)致的阻塞現(xiàn)象

又一次失敗了
我就繼續(xù)想啊想,就想到了InputStream提供的available()方法,這個(gè)方法返回的是下一次讀取的估計(jì)字節(jié)數(shù),當(dāng)初我就看到了這個(gè)方法,但是看到文檔上說的這個(gè)方法不建議使用,就一直沒想用。。。真是到了無可奈何啊。只好又試試這個(gè)方法的效果
于是呢,我就用了這種方法:
????? 在每一次循環(huán)讀取之前判斷InputStream剩余的字節(jié)數(shù)是不是 0 、即剩余字節(jié)是不是空的,如果是空的就不讀了,這種方法果然奏效!!! 但是經(jīng)過我的反復(fù)測試啊,發(fā)現(xiàn)又出現(xiàn)了一個(gè)問題,同一個(gè)瀏覽器的同一個(gè)頁面如果刷新的話,這個(gè)頁面第一次請(qǐng)求時(shí)候available() 正常, 下來的請(qǐng)求就不正常了,available()直接就 == 0 了, 第一次頁面請(qǐng)求 之后 的每一次頁面刷新后臺(tái)都讀取不到請(qǐng)求數(shù)據(jù)。 Socket我都關(guān)閉了啊!怎么會(huì)出現(xiàn)這種情況??? 納悶了, 又找了好長時(shí)間的資料,仍然沒有解決辦法。好像是上一次處理的InputStream的available()保留下來了一樣,但是如果另開一個(gè)頁面請(qǐng)求就正常。。。。
? ?
然后就是我想到的終極解決辦法了, 我假設(shè)的是 用戶請(qǐng)求內(nèi)容不可能是空值 ,于是,我就用了do{}while循環(huán),先執(zhí)行讀取一次,在判斷available()的值是不是0,這樣就保證了上一個(gè)問題的影響。 至于為什么這么做,我也是說不明白的,就是當(dāng)時(shí)的一種靈感吧。。。我感覺是為了把InputStream讀取指針先放在流頭。這樣可以避免干擾。

? ? ? 額語文水平很低啊、看的同學(xué)們勉強(qiáng)湊合吧
? ? ? 小弟現(xiàn)在大二,經(jīng)驗(yàn)有限,高手老鳥輕噴啊
第一次發(fā)不會(huì)貼代碼、試試吧!

主服務(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";	//綁定的主機(jī)127.0.0.1,不設(shè)置也可、默認(rèn)即為IP或localhost
	private final int BACKLOG = 1;				//最大請(qǐng)求并發(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{
				//偵測一次請(qǐng)求
				final Socket socket = server.accept();
				final InputStream in = socket.getInputStream();
				final OutputStream out = socket.getOutputStream();
				//多線程機(jī)制響應(yīng)請(qǐng)求
				new Thread(){
					public void run() {
						try {
							//處理響應(yīng)偵探到的請(qǐng)求
							MyRequest request = new MyRequest(in);
							request.Parse();
							MyResponse response = new MyResponse(out);
							response.setRequest(request);
							response.SendResponse();
							//本次請(qǐng)求處理結(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();
	}
	
}


  

請(qǐng)求處理類
    
package server.test01;

import java.io.IOException;
import java.io.InputStream;

public class MyRequest {
	
	private InputStream in;				//請(qǐng)求的輸入流
	private String uri;					//請(qǐng)求的uri
	private String request = "";		//請(qǐng)求處理后的字符串
	
	public MyRequest( InputStream in ) {
		this.in = in;
	}
	public String getUri() {
		return uri;
	}
	
	/**
	 * 提供對(duì)request請(qǐng)求的解析服務(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 "";
		}
	}
	
}

  

另外一個(gè)相應(yīng)類MyResponse就不貼了。。。

WEB服務(wù)器工作機(jī)制由淺至深(1):多線程模擬服務(wù)器并防止阻塞


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論