Java java지도 시간 Java URL 사용자 정의 개인 네트워크 프로토콜

Java URL 사용자 정의 개인 네트워크 프로토콜

Jan 05, 2017 pm 05:03 PM

——声明,脑残人士远离,本博客的核心不是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(<a href="http://www.apptest.com:8080/test/ios.php">http://www.apptest.com:8080/test/ios.php</a>);
로그인 후 복사

我们也要习惯

当然,我们还要让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(&#39;php://input&#39;, &#39;r&#39;);
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(&#39;text.html&#39;,$rs);echo &#39;写入成功&#39;;
로그인 후 복사

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();
로그인 후 복사

运行结果

Java URL 사용자 정의 개인 네트워크 프로토콜

结果说明,协议确实定义成功了


当然,如上数据解析不符合我们的要求,因为是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());
로그인 후 복사

    

更多Java URL自定义私有网络协议相关文章请关注PHP中文网!


본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25 : Myrise에서 모든 것을 잠금 해제하는 방법
4 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

Java의 클래스로드 메커니즘은 다른 클래스 로더 및 대표 모델을 포함하여 어떻게 작동합니까? Java의 클래스로드 메커니즘은 다른 클래스 로더 및 대표 모델을 포함하여 어떻게 작동합니까? Mar 17, 2025 pm 05:35 PM

Java의 클래스 로딩에는 부트 스트랩, 확장 및 응용 프로그램 클래스 로더가있는 계층 적 시스템을 사용하여 클래스로드, 링크 및 초기화 클래스가 포함됩니다. 학부모 위임 모델은 핵심 클래스가 먼저로드되어 사용자 정의 클래스 LOA에 영향을 미치도록합니다.

카페인 또는 구아바 캐시와 같은 라이브러리를 사용하여 자바 애플리케이션에서 다단계 캐싱을 구현하려면 어떻게해야합니까? 카페인 또는 구아바 캐시와 같은 라이브러리를 사용하여 자바 애플리케이션에서 다단계 캐싱을 구현하려면 어떻게해야합니까? Mar 17, 2025 pm 05:44 PM

이 기사는 카페인 및 구아바 캐시를 사용하여 자바에서 다단계 캐싱을 구현하여 응용 프로그램 성능을 향상시키는 것에 대해 설명합니다. 구성 및 퇴거 정책 관리 Best Pra와 함께 설정, 통합 및 성능 이점을 다룹니다.

캐싱 및 게으른 하중과 같은 고급 기능을 사용하여 객체 관계 매핑에 JPA (Java Persistence API)를 어떻게 사용하려면 어떻게해야합니까? 캐싱 및 게으른 하중과 같은 고급 기능을 사용하여 객체 관계 매핑에 JPA (Java Persistence API)를 어떻게 사용하려면 어떻게해야합니까? Mar 17, 2025 pm 05:43 PM

이 기사는 캐싱 및 게으른 하중과 같은 고급 기능을 사용하여 객체 관계 매핑에 JPA를 사용하는 것에 대해 설명합니다. 잠재적 인 함정을 강조하면서 성능을 최적화하기위한 설정, 엔티티 매핑 및 모범 사례를 다룹니다. [159 문자]

고급 Java 프로젝트 관리, 구축 자동화 및 종속성 해상도에 Maven 또는 Gradle을 어떻게 사용합니까? 고급 Java 프로젝트 관리, 구축 자동화 및 종속성 해상도에 Maven 또는 Gradle을 어떻게 사용합니까? Mar 17, 2025 pm 05:46 PM

이 기사에서는 Java 프로젝트 관리, 구축 자동화 및 종속성 해상도에 Maven 및 Gradle을 사용하여 접근 방식과 최적화 전략을 비교합니다.

적절한 버전 및 종속성 관리로 Custom Java 라이브러리 (JAR Files)를 작성하고 사용하려면 어떻게해야합니까? 적절한 버전 및 종속성 관리로 Custom Java 라이브러리 (JAR Files)를 작성하고 사용하려면 어떻게해야합니까? Mar 17, 2025 pm 05:45 PM

이 기사에서는 Maven 및 Gradle과 같은 도구를 사용하여 적절한 버전 및 종속성 관리로 사용자 정의 Java 라이브러리 (JAR Files)를 작성하고 사용하는 것에 대해 설명합니다.

See all articles