-Declaración, mantente alejado de las personas con muerte cerebral. El núcleo de este blog no es el prefijo IF-Else+, sino cómo definir un protocolo privado a través del marco de procesamiento del protocolo de URL
La diferencia entre un URI y una URL
URI (identificador de recursos uniformes) Identificador de recursos uniformes; URL (Ubicación uniforme de recursos) Localizador de recursos uniformes (o localización de recursos unificados); URI es un concepto relativamente amplio. URL es un tipo de URI y un subconjunto del mecanismo de nombres de URI. Se puede decir que URI es abstracto y el uso específico de URL para localizar recursos. El URI generalmente apunta a no la ruta de recursos físicos, sino el identificador de recursos mapeado en todo el sistema. Las URL son cadenas utilizadas en Internet para describir los recursos de información, utilizados principalmente en varios programas de clientes y programas de servidor WWW. El uso de URL puede usar un formato unificado para describir varios recursos de información, incluidos archivos, direcciones y directorios del servidor, etc.
1. Primero prefacio
Estamos acostumbrados a http
Url url = nueva url (http://www.apptest.com:8080/test/ios.php);
También debemos acostumbrarnos
Por supuesto, también necesitamos acostumbrarnos a la URL.
"https", "ftp", "mailto", "telnet", "archivo", "ldap", "gopher", "jdbc", "rmi", "jndi", "jar", "doc", "netdoc", "nfs", "verbatim", "dedo", "systemresurce"
URL URL = nueva URL ("OsChina: //www.apptest.com: 8080/test/iOS.Php");Si no está acostumbrado, siempre ocurrirán las siguientes excepciones
java.net.malformedurexception: protocolo desconocido
Al usar AJAX en los navegadores de Android, los protocolos indefinidos no serán compatibles.
2. Comprensión de protocolos personalizados
Protocolo: en el mundo de la programación, el protocolo en sí es un conjunto de reglas de restricción de entrada/salida. Por lo tanto, nuestro protocolo exacto debe girar en torno a E/S, por lo que el protocolo aquí puede llamarse protocolo de E/S.
Iniciador de acuerdo: Solicitud
Responder del protocolo: respuesta
Las condiciones para el establecimiento del acuerdo son: la solicitud y la respuesta reconocen el mismo conjunto de acuerdos y se comunican de acuerdo con las limitaciones del acuerdo.
3. La relación entre el protocolo personalizado y la URL
En Java, ¿los protocolos personalizados requieren URL?
La respuesta es no.
De hecho, alrededor de E/S, nuestras definiciones de reglas están completamente en nuestras propias manos. No dice que la Tierra no se dará la vuelta después de dejar la URL, y Java será destruida.
¿Por qué personalizar el protocolo usando clases de URL?
La respuesta se debe a que la URL es un marco de procesamiento de comunicación de protocolo maduro.
El protocolo de URL personalizado mencionado aquí es esencialmente más sobre expandir el protocolo a través de las reglas existentes.
4. URL Práctica de protocolo privado personalizado
Sabemos que los protocolos personalizados requieren respuesta y solicitud, y ambas partes deben comprender completamente el acuerdo de cada uno. Por conveniencia aquí, utilizamos el servidor de protocolo HTTP como respuesta.
Aquí usamos NGNIX Server + PHP + FASTCGI para crear una respuesta, y el código de implementación es el siguiente
1. Defina la respuesta
<? Php $ raw_post_data = file_get_contents ('php: // input', 'r'); echo "-------/$ _ Post ------------------/N <br/>"; echo var_dump ($ _ post). "/norte"; echo "------- php: // entrada --------------/n <br/>"; Echo $ RAW_POST_DATA. "/n <br/>"; $ rs = json_encode ($ _ servidor); file_put_contents ('text.html', $ rs); echo '写入成功';2. Definir solicitud
2.1 Implementación de la fábrica URLStreamHandlerFactory, utilizada principalmente para generar procesadores de protocolo
La clase pública ECHourlStreamHandlerFactory implementa URLStreamHandlerFactory {public UrlStreamHandler CreateUrlStreamHandler (String Protocol) {// Personalice diferentes solicitudes de esquema a través del desvío aquí. Por supuesto, las personas con muerte cerebral piensan que este es el código central. URL es un marco de procesamiento de protocolo. Si if-else es el núcleo, es Oracle ir a la quiebra if (protocol.equals ("echo") || protocol.equals ("Oschina")) {return new EchourlStreamHandler (); // Instanciar el controlador de procesamiento del protocolo} return null; }}2.2 Implementación de URLStreamHandler, la función principal es generar el conector correspondiente del protocolo
La clase pública EchourlStreamHandler extiende URLStreamHandler {@OverrideProtected URLConnection OpenConnection (URL U) Lanza ioexception {return new eChourlConnection (u); // También podemos realizar el desvío correspondiente aquí}} 2.3 Implementar UrlConnection, que es la personalización de las reglas de comunicación del protocolo. Aquí usamos el protocolo HTTP como reglas de comunicación. Aquí imitamos las solicitudes de protocolo HTTP
(El siguiente es el código central. El protocolo HTTP prestado aquí. Por supuesto, puede interactuar con varios protocolos que usan WebSocket, SMTP y FTP, en lugar del prefijo IF-Else+URL que las personas muertas de cerebro me piden que lo admita )
public class EchourlConnection extiende UrlConnection {private Socket Connection = null; public final static int default_port = 80; public ECHourlConnection (url url) {super (url);} public sincronizado inputStream getInputStream () lanza IOException {if (! Connected) {Connect (); OutputStream getOutputPutStream () lanza IOException {if (! Connected) {Connect ();} return Connection.getOutputStream ();} public String public getContentType () {return "Text/Plain";} public SynChronized void Connect () lanza IOEXEXCEI 65535) puerto = default_port; this.connection = new Socket (url.gethost (), puerto); // Verdadero significa desactivar el almacenamiento en búfer del socket y enviar datos inmediatamente. El valor predeterminado es falso // Si la implementación subyacente de Socket no admite la opción TCP_NODELAY, SocketExceptionthis.connection.settcpnodelay (verdadero); // indica si la dirección local se permite que se acerque a la dirección local a la dirección local a la dirección local a la dirección local. this.connection.setReuseAddress(true);// Indicates the waiting timeout when receiving data, in milliseconds.. The default value is 0, which means that there will be infinite waiting and will never timeout// When reading data through the Socket input stream, if there is no data, it will wait// After the timeout, the SocketTimeoutException will be thrown, and after the exception is thrown, the Socket is still connected, you can try to Lea los datos nuevamente esto.connection.setSotimeOut (30000); // Indica si el enchufe subyacente se cierra inmediatamente // Cuando el enchufe está cerrado, el enchufe subyacente se retrasará en 5 segundos y luego se cerrará nuevamente. Después de 5 segundos, todos los datos restantes que no se han enviado serán descartados. De manera predeterminada, si el método Socket.Close () se ejecuta, el método regresará de inmediato, pero el socket subyacente no está cerrado de inmediato // se retrasará por un período de tiempo hasta que se envíen todos los datos restantes, y el socket se cerrará verdaderamente y se desconectará // Tips: cuando el programa escriba los datos a través de la transmisión de salida, solo significa que el programa envía una lote de datos a la red, y la red es responsable de la red de los datos de la salida de la salida. Cuando el programa cierra el socket, es posible que el lote de datos todavía se transmitiera en la red y no haya alcanzado el receptor // consejos: los "datos restantes" mencionados "mencionados aquí se refieren a estos datos que aún se transmiten en la red y no ha sido recibido por el receptor this.connection.setsolinger (verdadero, 5); // indica el tamaño del buffer donde el datos está enviado está enviado el datos que se envían se envían los datos que están enviadas se envían los datos que se envían los datos están enviadas se envían el datos que se envían los datos están enviadas. this.connection.setSendBufferSize (1024); // Indica el tamaño del búfer donde se reciben los datos this.connection.setReceiveBufferSize (1024); // no transmitir datos entre sí)? Verdadero es sí // Su valor predeterminado es falso, lo que significa que TCP no monitoreará si la conexión es válida, y los clientes inactivos pueden existir permanentemente sin previo aviso de que el servidor se ha bloqueado esto.connection.setkeepalive (verdadero); // Indica si admite el envío de un byte de datos de emergencia TCP. Socket.sendurgentData (datos) se usa para enviar un byte de datos de emergencia de TCP // El valor predeterminado es falso, es decir, el receptor no realiza ningún procesamiento al recibir los datos de emergencia y lo descarta directamente. Si el usuario desea enviar datos de emergencia, debe establecerse en True // Después de configurarlo en True, el receptor colocará los datos de emergencia recibidos en la misma cola que los datos normales this.connection.setoobinline (verdadero); // Este método se utiliza para establecer el tipo de servicio. El siguiente código solicita una alta confiabilidad y un servicio de transmisión de retraso mínimo (bits u operaciones de 0x04 y 0x10) // La clase de socket usa 4 enteros para representar el tipo de servicio // 0x02: bajo costo (el penúltimo bit de binario es 1) // 0x04: Alta confiabilidad (el bit de bidón de binario es 1) // 0x08: el máximo de máximo (el bit de cuatro penultimate de cuatro penultimas es 1). 0x10: Retraso mínimo (el quinto penúltimo bit de binario es 1) this.connection.setTrafficClass (0x04 | 0x10); // Este método se utiliza para establecer la importancia relativa del tiempo de conexión, el retraso y el ancho de banda (los tres parámetros de este método representan tres indicadores de datos de transmisión de red) // El tiempo de conexión del tiempo de conexión significa establecer una conexión con el tiempo minimum ////// Latencia --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 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.get Host ()). Append (":"). Append (url.getport ()). Append ("/r/n");} sb.append ("Connection: Keep-alive/r/n"); sb.append ("Fecha: fri, 22 de abril de 2016 13:17:35 GMT/R/N "); sb.append (" variar: aceptar-ending/r/n "); sb.append (" Tipo de contenido: aplicación/x-www-form-urlencoded, charset = utf-8/r/n "); sb.append (" Longitud de contenido::::::::::: ") .Append (" name = zhangsan & contraseña = 123456 ".getBytes (" utf-8 "). longitud) .append ("/r/n "); sb.append ("/r/n "); this.connection.getOutputStream (). Write (sb.ToString (). disconnect () lanza ioexception {if (conectado) {this.connection.close (); this.connected = false;}}} Aquí, la definición del protocolo se ha completado.
Nuestro código de prueba es el siguiente
Intente conectarse a 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 conexión = (ECHourlConnection) URL.Openconnection (); Connect.SetDoOutput (true); Connect.SetDoInput (verdadero); 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/r/r/n") && len <256) {// El servidor devuelve una codificación de transferencia,/r/n0/r/n/r/n significa que la lectura ha finalizado, análisis de codificación: http://dbscx.iteye.com/blog/830644 line = line. line.length ()-"/r/n0/r/n/r/n" .length ()); System.out.println (línea); romper; } else {System.out.println (línea); }} pw.close (); stream.close ();Resultados de ejecución
El resultado muestra que el protocolo se ha definido con éxito
Por supuesto, el análisis de datos anterior no cumple con nuestros requisitos porque es información de codificación. Cómo analizarlo cumple con los requisitos, muévete :
Algoritmo de codificación y analización de datos fragmentados de HTTP
5. Más tarde, un analizador minero personalizado
ContentHandlerFactory se proporciona en Java para analizar minetype. Formulamos nuestro propio analizador aquí. Por supuesto, el JDK proporciona más abundantemente. Lo que hacemos aquí es para satisfacer las necesidades especiales.
public class EchocontentHandler extiende ContentHandler {public Object getContent (urlconnection Connection) lanza IOException {inputStream in = Connection.getInputStream (); BufferedReader BR = New BufferedReader (New InputStreamReader (in)); return BR.EntRe = conexión.getInputStream (); for (int i = 0; i <classes.length; i ++) {if (classes [i] == inputStream.class) return en; else if (classes [i] == string.class) return getContent (conexión);} return null;}}El uso es muy simple
Urlconnection.setContentHandLerFactory (new EchocontentHandLerFactory ());