一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務(wù)器之家 - 編程語言 - JAVA教程 - Java URL自定義私有網(wǎng)絡(luò)協(xié)議

Java URL自定義私有網(wǎng)絡(luò)協(xié)議

2020-04-22 11:32IamOkay JAVA教程

URI與URL的區(qū)別 一.先來序言一段 二.協(xié)議的自定義的理解 三.自定義協(xié)議與URL的關(guān)系 四.URL自定義私有協(xié)議實戰(zhàn) 五.后話,自定義mineType解析器

——聲明,腦殘人士遠離,本博客的核心不是if-else+前綴,而是如何通過URL協(xié)議處理框架定義私有協(xié)議

URI與URL的區(qū)別

?
1
URI (uniform resource identifier)統(tǒng)一資源標(biāo)志符;URL(uniform resource location )統(tǒng)一資源定位符(或統(tǒng)一資源定位器);URI是一個相對來說更廣泛的概念,URL是URI的一種,是URI命名機制的一個子集,可以說URI是抽象的,而具體要使用URL來定位資源。URI指向的一般不是物理資源路徑,而是整個系統(tǒng)中的映射后的資源標(biāo)識符。URL是Internet上用來描述信息資源的字符串,主要用在各種WWW客戶程序和服務(wù)器程序上。采用URL可以用一種統(tǒng)一的格式來描述各種信息資源,包括文件、服務(wù)器的地址和目錄等。


一.先來序言一段

我們習(xí)慣了http

?
1
URL url=new URL(<a href="http://www.apptest.com:8080/test/ios.php">http://www.apptest.com:8080/test/ios.php</a>);

我們也要習(xí)慣

當(dāng)然,我們還要讓URL習(xí)慣我們

?
1
"https", "ftp", "mailto", "telnet", "file", "ldap", "gopher", "jdbc", "rmi", "jndi", "jar", "doc", "netdoc", "nfs", "verbatim", "finger", "daytime", "systemresource"
?
1
URL url=new URL("oschina://www.apptest.com:8080/test/ios.php");

如果不習(xí)慣,總會出現(xiàn)如下異常

?
1
java.net.MalformedURLException: unknown protocol

在Android瀏覽器使用Ajax時也會不支持沒有定義的過的協(xié)議。

 

二.協(xié)議的自定義的理解

協(xié)議:在編程的世界里,協(xié)議本身就是一套Input/ouput約束規(guī)則,因此,我們確切的協(xié)議應(yīng)該圍繞I/O展開的,所以,這里的協(xié)議可以稱為I/O協(xié)議。

協(xié)議發(fā)起方:request

協(xié)議響應(yīng)方:response

協(xié)議成立的條件是:request和reponse認可同一套協(xié)議,并按照協(xié)議約束進行通信。

 

三.自定義協(xié)議與URL的關(guān)系

在java中,自定義協(xié)議一定需要用URL嗎?

答案是否定的。

 事實上,圍繞I/O,我們的規(guī)則定義完全有我們本身掌握,并沒有說離開URL地球不轉(zhuǎn)了,Java要毀滅了。

為什么使用URL類來自定義協(xié)議?

答案是因為URL是一套成熟的協(xié)議通信處理框架。

這里說的自定義URL協(xié)議,實質(zhì)上更多的是通過已有的規(guī)則進行擴充協(xié)議。

四.URL自定義私有協(xié)議實戰(zhàn)

我們知道,自定義協(xié)議需要Response 和Request,雙方需要充理解對方的協(xié)議。這里為了方便起見,我們使用Http協(xié)議服務(wù)器來作為Response。

這里我們使用了Ngnix服務(wù)器+PHP+FastCGI來構(gòu)建Reponse,部署代碼如下

1.定義Response

?
1
2
3
4
5
6
<?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實現(xiàn)URLStreamHandlerFactory工廠,主要用來產(chǎn)生協(xié)議處理器

?
1
2
3
4
5
6
7
public class EchoURLStreamHandlerFactory implements URLStreamHandlerFactory {
public URLStreamHandler createURLStreamHandler(String protocol){
//通過這里的分流處理不同的schema請求,當(dāng)然腦殘人士認為這里才是核心代碼,URL是一套協(xié)議處理框架,如果if-else就是核心,是不是oracle要倒閉 
if(protocol.equals("echo") || protocol.equals("oschina"))   {
   return new EchoURLStreamHandler(); //實例化協(xié)議處理Handler 
 
return null; }}

2.2實現(xiàn)URLStreamHandler,主要作用是生成協(xié)議對應(yīng)的連接器

?
1
2
3
4
5
public class EchoURLStreamHandler extends URLStreamHandler {
@Overrideprotected URLConnection openConnection(URL u) throws IOException {
return new EchoURLConnection(u);
//在這里我們也可以進行相應(yīng)的分流}
}

2.3  實現(xiàn)URLConnection,作用是協(xié)議通信規(guī)則的自定義,這里我們使用HTTP協(xié)議作為通信規(guī)則,我們這里仿制http協(xié)議請求

(以下才是核心代碼,這里借用的http協(xié)議,當(dāng)然你可以用websocket,smtp,ftp各種協(xié)議進行交互,而不是腦殘人士讓我承認的 if-else+URL前綴

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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表示關(guān)閉Socket的緩沖,立即發(fā)送數(shù)據(jù)..其默認值為false//
若Socket的底層實現(xiàn)不支持TCP_NODELAY選項,則會拋出SocketExceptionthis.connection.setTcpNoDelay(true);
// 表示是否允許重用Socket所綁定的本地地址this.connection.setReuseAddress(true);
// 表示接收數(shù)據(jù)時的等待超時時間,單位毫秒..其默認值為0,表示會無限等待,永遠不會超時
// 當(dāng)通過Socket的輸入流讀數(shù)據(jù)時,如果還沒有數(shù)據(jù),就會等待
// 超時后會拋出SocketTimeoutException,且拋出該異常后Socket仍然是連接的,可以嘗試再次讀數(shù)據(jù)this.connection.setSoTimeout(30000);
// 表示當(dāng)執(zhí)行Socket.close()時,是否立即關(guān)閉底層的Socket
// 這里設(shè)置為當(dāng)Socket關(guān)閉后,底層Socket延遲5秒后再關(guān)閉,而5秒后所有未發(fā)送完的剩余數(shù)據(jù)也會被丟棄
// 默認情況下,執(zhí)行Socket.close()方法,該方法會立即返回,但底層的Socket實際上并不立即關(guān)閉
// 它會延遲一段時間,直到發(fā)送完所有剩余的數(shù)據(jù),才會真正關(guān)閉Socket,斷開連接
// Tips:當(dāng)程序通過輸出流寫數(shù)據(jù)時,僅僅表示程序向網(wǎng)絡(luò)提交了一批數(shù)據(jù),由網(wǎng)絡(luò)負責(zé)輸送到接收方
// Tips:當(dāng)程序關(guān)閉Socket,有可能這批數(shù)據(jù)還在網(wǎng)絡(luò)上傳輸,還未到達接收方
// Tips:這里所說的"未發(fā)送完的剩余數(shù)據(jù)"就是指這種還在網(wǎng)絡(luò)上傳輸,未被接收方接收的數(shù)據(jù)this.connection.setSoLinger(true, 5);
// 表示發(fā)送數(shù)據(jù)的緩沖區(qū)的大小this.connection.setSendBufferSize(1024);
// 表示接收數(shù)據(jù)的緩沖區(qū)的大小this.connection.setReceiveBufferSize(1024);
// 表示對于長時間處于空閑狀態(tài)(連接的兩端沒有互相傳送數(shù)據(jù))的Socket,是否要自動把它關(guān)閉,true為是
// 其默認值為false,表示TCP不會監(jiān)視連接是否有效,不活動的客戶端可能會永久存在下去,而不會注意到服務(wù)器已經(jīng)崩潰this.connection.setKeepAlive(true);
// 表示是否支持發(fā)送一個字節(jié)的TCP緊急數(shù)據(jù),socket.sendUrgentData(data)用于發(fā)送一個字節(jié)的TCP緊急數(shù)據(jù)
// 其默認為false,即接收方收到緊急數(shù)據(jù)時不作任何處理,直接將其丟棄..若用戶希望發(fā)送緊急數(shù)據(jù),則應(yīng)設(shè)其為true
// 設(shè)為true后,接收方會把收到的緊急數(shù)據(jù)與普通數(shù)據(jù)放在同樣的隊列中this.connection.setOOBInline(true);
// 該方法用于設(shè)置服務(wù)類型,以下代碼請求高可靠性和最小延遲傳輸服務(wù)(把0x04與0x10進行位或運算)
// Socket類用4個整數(shù)表示服務(wù)類型// 0x02:低成本(二進制的倒數(shù)第二位為1)
// 0x04:高可靠性(二進制的倒數(shù)第三位為1)// 0x08:最高吞吐量(二進制的倒數(shù)第四位為1)
// 0x10:最小延遲(二進制的倒數(shù)第五位為1)this.connection.setTrafficClass(0x04 | 0x10);
// 該方法用于設(shè)定連接時間,延遲,帶寬的相對重要性(該方法的三個參數(shù)表示網(wǎng)絡(luò)傳輸數(shù)據(jù)的3項指標(biāo))
// connectionTime--該參數(shù)表示用最少時間建立連接
// latency---------該參數(shù)表示最小延遲
// bandwidth-------該參數(shù)表示最高帶寬// 可以為這些參數(shù)賦予任意整數(shù)值,這些整數(shù)之間的相對大小就決定了相應(yīng)參數(shù)的相對重要性/
// 如這里設(shè)置的就是---最高帶寬最重要,其次是最小連接時間,最后是最小延遲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;}}}

在這里,協(xié)議定義已經(jīng)完成。

我們測試代碼如下

嘗試連接  oschina://localhost:8080/test/ios.php

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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 = -1byte[] 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)   {   
     //服務(wù)器返回的是Transfer-chunked編碼,\r\n0\r\n\r\n表示讀取結(jié)束了,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();

運行結(jié)果

Java URL自定義私有網(wǎng)絡(luò)協(xié)議

結(jié)果說明,協(xié)議確實定義成功了

 

當(dāng)然,如上數(shù)據(jù)解析不符合我們的要求,因為是chunked編碼信息,如何解析符合要求有,請移步

HTTP Chunked數(shù)據(jù)編碼與解析算法

五.后話,自定義mineType解析器

java中提供了ContentHandlerFactory,用來解析mineType,我們這里制定我們自己的解析器,當(dāng)然,JDK中提供的更豐富,這里所做的只是為了符合特殊需求

?
1
2
3
4
5
6
7
8
9
10
11
12
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;}}

用法很簡單

?
1
URLConnection.setContentHandlerFactory(new EchoContentHandlerFactory());

 

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 精品一区heyzo在线播放 | 精品女同同性视频很黄很色 | 男男playh片在线观看 | 国产精品亚洲精品日韩已满 | 千金在线观看 | 国产suv精品一区二区四区三区 | 免费看男女做好爽好硬视频 | 四虎2023| 国产自产自拍 | 日韩欧美高清 | 暖暖 免费 高清 日本 在线1 | 日韩精品成人免费观看 | 操破苍穹小说 | 关晓彤被调教出奶水的视频 | a在线观看欧美在线观看 | 韩国理论三级在线观看视频 | 亚洲天堂精品在线观看 | 久久精品国产亚洲AV麻豆欧美玲 | 日韩高清一区二区 | 亚洲 日韩 自拍 视频一区 | 国产欧美一区视频在线观看 | 校花被扒开尿口折磨憋尿 | 亚洲成人第一页 | jizzjizz大学生 | 亚洲精品影视 | 色狠狠婷婷97 | 国产一区二区三区四区波多野结衣 | 久久水蜜桃亚洲AV无码精品偷窥 | 欧美综合国产精品日韩一 | 日本漫画工囗全彩内番e绅 日本伦理动漫在线观看 | 色鬼网 | 国产亚洲精品精品国产亚洲综合 | 无遮无挡免费视频 | 美女的让男人桶爽免费看 | 日本伊人久久 | 日本成熟bbxxxxxxxx | 亚洲色域网 | 亚洲欧美日韩另类在线 | 极品丝袜老师h系列全文阅读 | 亚洲狼人香蕉香蕉在线28 | 色噜噜国产精品视频一区二区 |