Java URL自界說公有收集協定。本站提示廣大學習愛好者:(Java URL自界說公有收集協定)文章只能為提供參考,不一定能成為您想要的結果。以下是Java URL自界說公有收集協定正文
——聲明,腦殘人士闊別,本博客的焦點不是if-else+前綴,而是若何經由過程URL協定處置框架界說公有協定
URI與URL的差別
URI (uniform resource identifier)同一資本標記符;URL(uniform resource location )同一資本定位符(或同一資本定位器);URI是一個絕對來講更普遍的概念,URL是URI的一種,是URI定名機制的一個子集,可以說URI是籠統的,而詳細要應用URL來定位資本。URI指向的普通不是物理資本途徑,而是全部體系中的映照後的資本標識符。URL是Internet上用來描寫信息資本的字符串,重要用在各類WWW客戶法式和辦事器法式上。采取URL可以用一種同一的格局來描寫各類信息資本,包含文件、辦事器的地址和目次等。
一.先來序文一段
我們習氣了http
URL url=new URL(http://www.apptest.com:8080/test/ios.php);
我們也要習氣
固然,我們還要讓URL習氣我們
"https", "ftp", "mailto", "telnet", "file", "ldap", "gopher", "jdbc", "rmi", "jndi", "jar", "doc", "netdoc", "nfs", "verbatim", "finger", "daytime", "systemresource"
URL url=new URL("oschina://www.apptest.com:8080/test/ios.php");
假如不習氣,總會湧現以下異常
java.net.MalformedURLException: unknown protocol
在Android閱讀器應用Ajax時也會不支撐沒有界說的過的協定。
二.協定的自界說的懂得
協定:在編程的世界裡,協定自己就是一套Input/ouput束縛規矩,是以,我們確實的協定應當環繞I/O睜開的,所以,這裡的協定可以稱為I/O協定。
協定提議方:request
協定呼應方:response
協定成立的前提是:request和reponse承認統一套協定,並依照協定束縛停止通訊。
三.自界說協定與URL的關系
在java中,自界說協定必定須要用URL嗎?
謎底能否定的。
現實上,環繞I/O,我們的規矩界說完整有我們自己控制,並沒有說分開URL地球不轉了,Java要撲滅了。
為何應用URL類來自界說協定?
謎底是由於URL是一套成熟的協定通訊處置框架。
這裡說的自界說URL協定,本質上更多的是經由過程已有的規矩停止擴大協定。
四.URL自界說公有協定實戰
我們曉得,自界說協定須要Response 和Request,兩邊須要充懂得對方的協定。這裡為了便利起見,我們應用Http協定辦事器來作為Response。
這裡我們應用了Ngnix辦事器+PHP+FastCGI來構建Reponse,安排代碼以下
1.界說Response
<?php$raw_post_data = file_get_contents('php://input', 'r'); echo "-------\$_POST------------------\n<br/>"; echo var_dump($_POST) . "\n"; echo "-------php://input-------------\n<br/>"; echo $raw_post_data . "\n<br/>"; $rs = json_encode($_SERVER);file_put_contents('text.html',$rs);echo '寫入勝利';
2.界說Request
2.1完成URLStreamHandlerFactory工場,重要用來發生協定處置器
public class EchoURLStreamHandlerFactory implements URLStreamHandlerFactory { public URLStreamHandler createURLStreamHandler(String protocol){ //經由過程這裡的分流處置分歧的schema要求,固然腦殘人士以為這裡才是焦點代碼,URL是一套協定處置框架,假如if-else就是焦點,是否是oracle要開張 if(protocol.equals("echo") || protocol.equals("oschina")) { return new EchoURLStreamHandler(); //實例化協定處置Handler } return null; }}
2.2完成URLStreamHandler,重要感化是生成協定對應的銜接器
public class EchoURLStreamHandler extends URLStreamHandler { @Overrideprotected URLConnection openConnection(URL u) throws IOException { return new EchoURLConnection(u); //在這裡我們也能夠停止響應的分流} }
2.3 完成URLConnection,感化是協定通訊規矩的自界說,這裡我們應用HTTP協定作為通訊規矩,我們這裡仿造http協定要求
(以下才是焦點代碼,這裡借用的http協定,固然你可以用websocket,smtp,ftp各類協定停止交互,而不是腦殘人士讓我認可的 if-else+URL前綴)
public class EchoURLConnection extends URLConnection { private Socket connection = null; public final static int DEFAULT_PORT = 80;public EchoURLConnection(URL url) { super(url);} public synchronized InputStream getInputStream() throws IOException { if (!connected) {connect(); } return connection.getInputStream(); } public synchronized OutputStream getOutputStream() throws IOException { if (!connected) {connect(); } return connection.getOutputStream(); } public String getContentType() { return "text/plain"; }public synchronized void connect() throws IOException { if (!connected) { int port = url.getPort(); if (port < 0 || port > 65535)port = DEFAULT_PORT; this.connection = new Socket(url.getHost(), port); // true表現封閉Socket的緩沖,立刻發送數據..其默許值為false// 若Socket的底層完成不支撐TCP_NODELAY選項,則會拋出SocketExceptionthis.connection.setTcpNoDelay(true); // 表現能否許可重用Socket所綁定的當地地址this.connection.setReuseAddress(true); // 表現吸收數據時的期待超不時間,單元毫秒..其默許值為0,表現會無窮期待,永久不會超時 // 當經由過程Socket的輸出流讀數據時,假如還沒稀有據,就會期待 // 超時後會拋出SocketTimeoutException,且拋出該異常後Socket依然是銜接的,可以測驗考試再次讀數據this.connection.setSoTimeout(30000); // 表現當履行Socket.close()時,能否立刻封閉底層的Socket // 這裡設置為當Socket封閉後,底層Socket延遲5秒後再封閉,而5秒後一切未發送完的殘剩數據也會被拋棄 // 默許情形下,履行Socket.close()辦法,該辦法會立刻前往,但底層的Socket現實上其實不立刻封閉 // 它會延遲一段時光,直到發送完一切殘剩的數據,才會真正封閉Socket,斷開銜接 // Tips:當法式經由過程輸入流寫數據時,僅僅表現法式向收集提交了一批數據,由收集擔任保送到吸收方 // Tips:當法式封閉Socket,有能夠這批數據還在收集上傳輸,還未達到吸收方 // Tips:這裡所說的"未發送完的殘剩數據"就是指這類還在收集上傳輸,未被吸收方吸收的數據this.connection.setSoLinger(true, 5); // 表現發送數據的緩沖區的年夜小this.connection.setSendBufferSize(1024); // 表現吸收數據的緩沖區的年夜小this.connection.setReceiveBufferSize(1024); // 表現關於長時光處於余暇狀況(銜接的兩頭沒有相互傳送數據)的Socket,能否要主動把它封閉,true為是 // 其默許值為false,表現TCP不會監督銜接能否有用,不運動的客戶端能夠會永遠存鄙人去,而不會留意到辦事器曾經瓦解this.connection.setKeepAlive(true); // 表現能否支撐發送一個字節的TCP緊迫數據,socket.sendUrgentData(data)用於發送一個字節的TCP緊迫數據 // 其默許為false,即吸收方收到緊迫數據時不作任何處置,直接將其拋棄..若用戶願望發送緊迫數據,則應設其為true // 設為true後,吸收方會把收到的緊迫數據與通俗數據放在異樣的隊列中this.connection.setOOBInline(true); // 該辦法用於設置辦事類型,以下代碼要求高靠得住性和最小延遲傳輸辦事(把0x04與0x10停止位或運算) // Socket類用4個整數表現辦事類型// 0x02:低本錢(二進制的倒數第二位為1) // 0x04:高靠得住性(二進制的倒數第三位為1)// 0x08:最高吞吐量(二進制的倒數第四位為1) // 0x10:最小延遲(二進制的倒數第五位為1)this.connection.setTrafficClass(0x04 | 0x10); // 該辦法用於設定銜接時光,延遲,帶寬的絕對主要性(該辦法的三個參數表現收集傳輸數據的3項目標) // connectionTime--該參數表現用起碼時光樹立銜接 // latency---------該參數表現最小延遲 // bandwidth-------該參數表現最高帶寬// 可認為這些參數付與隨意率性整數值,這些整數之間的絕對年夜小就決議了響應參數的絕對主要性/ // 如這裡設置的就是---最高帶寬最主要,其次是最小銜接時光,最初是最小延遲this.connection.setPerformancePreferences(2, 1, 3);this.connected = true;StringBuilder sb = new StringBuilder();sb.append("POST " + url.getPath() + " HTTP/1.1 \r\n"); //if(url.getPort()<0 || url.getPort()>65536){sb.append("Host:").append(url.getHost()).append("\r\n");}else{sb.append("Host:").append(url.getHost()).append(":").append(url.getPort()).append("\r\n");}sb.append("Connection:keep-alive\r\n");sb.append("Date:Fri, 22 Apr 2016 13:17:35 GMT\r\n");sb.append("Vary:Accept-Encoding\r\n");sb.append("Content-Type: application/x-www-form-urlencoded,charset=utf-8\r\n");sb.append("Content-Length: ").append("name=zhangsan&password=123456".getBytes("UTF-8").length).append("\r\n");sb.append("\r\n");this.connection.getOutputStream().write(sb.toString().getBytes("UTF-8"));}}public synchronized void disconnect() throws IOException {if (connected) {this.connection.close();this.connected = false;}}}
在這裡,協定界說曾經完成。
我們測試代碼以下
測驗考試銜接 oschina://localhost:8080/test/ios.php
URL.setURLStreamHandlerFactory(new EchoURLStreamHandlerFactory()); // URLConnection.setContentHandlerFactory(new EchoContentHandlerFactory()); URL url=new URL("oschina://localhost:8080/test/ios.php"); EchoURLConnection connection=(EchoURLConnection)url.openConnection(); connection.setDoOutput(true);connection.setDoInput(true); PrintWriter pw = new PrintWriter(new OutputStreamWriter(connection.getOutputStream())); pw.write("name=zhangsan&password=123456");pw.flush(); InputStream stream = connection.getInputStream(); int len = -1; byte[] buf = new byte[256]; while((len=stream.read(buf, 0, 256))>-1) { String line = new String(buf, 0, len); if(line.endsWith("\r\n0\r\n\r\n")&&len<256) { //辦事器前往的是Transfer-chunked編碼,\r\n0\r\n\r\n表現讀取停止了,chunked編碼解析:http://dbscx.iteye.com/blog/830644 line = line.substring(0, line.length()-"\r\n0\r\n\r\n".length()); System.out.println(line); break; }else{ System.out.println(line); } } pw.close(); stream.close();
運轉成果
成果解釋,協定確切界說勝利了
固然,如上數據解析不相符我們的請求,由於是chunked編碼信息,若何解析相符請求有,請移步:
HTTP Chunked數據編碼與解析算法
五.後話,自界說mineType解析器
java中供給了ContentHandlerFactory,用來解析mineType,我們這裡制訂我們本身的解析器,固然,JDK中供給的更豐碩,這裡所做的只是為了相符特別需求
public class EchoContentHandler extends ContentHandler { public Object getContent(URLConnection connection) throws IOException { InputStream in = connection.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(in)); return br.readLine(); } public Object getContent(URLConnection connection, Class[] classes) throws IOException {InputStream in = connection.getInputStream(); for (int i = 0; i < classes.length; i++) { if (classes[i] == InputStream.class)return in; else if (classes[i] == String.class)return getContent(connection); }return null;}}
用法很簡略
URLConnection.setContentHandlerFactory(new EchoContentHandlerFactory());