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());