- Déclaration, évitez les personnes mortes du cerveau. Le cœur de ce blog n'est pas le préfixe IF-Else +, mais comment définir un protocole privé via le cadre de traitement du protocole URL
La différence entre un URI et une URL
URI (identifiant de ressources uniformes) identifiant de ressources uniformes; URL (emplacement des ressources uniformes) Locator de ressources uniformes (ou localisateur de ressources unifié); URI est un concept relativement large. L'URL est un type d'URI et un sous-ensemble du mécanisme de dénomination de l'URI. On peut dire que l'URI est abstrait et l'utilisation spécifique des URL pour localiser les ressources. L'URI pointe généralement non pas le chemin de la ressource physique, mais l'identifiant de ressources mappé dans l'ensemble du système. Les URL sont des chaînes utilisées sur Internet pour décrire les ressources d'information, principalement utilisées sur divers programmes clients et programmes de serveur WWW. L'utilisation des URL peut utiliser un format unifié pour décrire diverses ressources d'information, y compris les fichiers, les adresses du serveur et les répertoires, etc.
1. Firstons la préface
Nous sommes habitués à http
Url url = new URL (http://www.apptest.com:8080/test/ios.php);
Nous devons nous y habituer aussi
Bien sûr, nous devons également nous habituer à l'URL.
"https", "ftp", "mailto", "telnet", "file", "ldap", "gopher", "jdbc", "rmi", "jndi", "jar", "doc", "netdoc", "nfs", "verbatim"
Url url = new URL ("oschina: //www.apptest.com: 8080 / test / ios.php");Si vous n'y êtes pas habitué, les exceptions suivantes se produiront toujours
java.net.malformedUrlexception: protocole inconnu
Lorsque vous utilisez AJAX dans les navigateurs Android, les protocoles non définis ne seront pas pris en charge.
2. Compréhension des protocoles personnalisés
Protocole: Dans le monde de la programmation, le protocole lui-même est un ensemble de règles de contrainte d'entrée / ouput. Par conséquent, notre protocole exact devrait tourner autour des E / S, de sorte que le protocole peut être appelé le protocole d'E / S.
Initiateur d'accord: demande
Répondant du protocole: réponse
Les conditions de création de l'accord sont: la demande et la réponse reconnaissent le même ensemble d'accords et communiquent en fonction des contraintes de l'accord.
3. La relation entre le protocole personnalisé et l'URL
En Java, les protocoles personnalisés nécessitent-ils des URL?
La réponse est non.
En fait, autour d'E / S, nos définitions de règles sont complètement entre nos mains. Il ne dit pas que la Terre ne se retournera pas après avoir quitté l'URL, et Java sera détruite.
Pourquoi personnaliser le protocole à l'aide de classes d'URL?
La réponse est parce que l'URL est un cadre de traitement de communication de protocole mature.
Le protocole URL personnalisé mentionné ici consiste essentiellement à étendre le protocole grâce à des règles existantes.
4. Pratique du protocole privé personnalisé de l'URL
Nous savons que les protocoles personnalisés nécessitent une réponse et une demande, et les deux parties doivent bien comprendre l'accord de chacun. Pour plus de commodité ici, nous utilisons le serveur de protocole HTTP en réponse.
Ici, nous utilisons NGIX Server + Php + FastCGI pour créer une réponse, et le code de déploiement est le suivant
1. Définir la réponse
<? php $ raw_post_data = file_get_contents ('php: // input', 'r'); echo "------- / $ _ Post ------------------ / n <br/>"; Echo var_dump ($ _ post). "/ n"; echo "------- php: // entrée ------------- / n <br/>"; echo $ raw_post_data. "/ n <br/>"; $ rs = json_encode ($ _ serveur); file_put_contents ('text.html', $ rs); echo '写入成功';2. Définir la demande
2.1 Implémentation de l'usine UrlstreamHandlerfactory, principalement utilisée pour générer des processeurs de protocole
classe publique EchourlStreamHandlerFactory implémente UrlStreamHandlerFactory {public UrlStreamHandler CreateUrlStreamHandler (String Protocol) {// Personnaliser différentes requêtes de schéma via la diversion ici. Bien sûr, les gens morts du cerveau pensent que c'est le code de base. L'URL est un cadre de traitement du protocole. Si if-else est le noyau, Oracle va faire faillite if (protoCol.equals ("echo") || protoCol.equals ("oschina")) {return new EchourlStreamHandler (); // instancier le gestionnaire de traitement du protocole} return null; }}2.2 Implémentation d'UrlstreamHandler, la fonction principale est de générer le connecteur correspondant du protocole
La classe publique EchourlStreamHandler étend UrlStreamHandler {@OverRideProtected URLConnection OpenConnection (URL U) lève IoException {return new EChourlConnection (u); // Nous pouvons également effectuer une diversion correspondante ici}} 2.3 Implémentation d'UrlConnection, qui est la personnalisation des règles de communication du protocole. Ici, nous utilisons le protocole HTTP comme règles de communication. Ici, nous imitons les demandes de protocole HTTP
(Ce qui suit est le code de base. Le protocole HTTP emprunté ici. Bien sûr, vous pouvez interagir avec divers protocoles à l'aide de WebSocket, SMTP et FTP, au lieu du préfixe IF-Else + URL que les gens mortels de cerveau me demandent )
classe publique EchourlConnection étend UrlConnection {private socket connection = null; public final static int Default_port = 80; public eChourlConnection (url url) {super (url);} public synchronisé inputStream getInputStream () lance ioexception {if (! Connected) {connect ();} return Connection Connection.getStream ();} Public Synchron. OutputStream getOutputStream () lève ioException {if (! Connecté) {connect ();} return connection.getOutputStream ();} public String getContentType () {return "text / plain";} public synchronisé void connect () lance ioexception {if (! Connecté) {int port = url.getport ();); 65535) port = default_port; this.connection = new Socket(url.getHost(), port);// true means to turn off the buffering of the Socket and send data immediately.. The default value is false// If the underlying implementation of Socket does not support the TCP_NODELAY option, SocketExceptionthis.connection.setTcpNoDelay(true);// Indicates whether reuse of the local address bound to the Socket is allowed this.connection.setReUSEaddress (true); // indique le délai d'attente lors de la réception de données, en millisecondes. Lisez à nouveau les données this.connection.SetSoTimeout (30000); // indique si la prise sous-jacente est immédiatement fermée // Lorsque la prise est fermée, la prise sous-jacente sera retardée de 5 secondes puis fermée à nouveau. Après 5 secondes, toutes les données restantes qui n'ont pas été envoyées seront rejetées. By default, if the Socket.close() method is executed, the method will return immediately, but the underlying Socket is not actually closed immediately// It will delay for a period of time until all the remaining data is sent, and the Socket will be truly closed and disconnected// Tips: When the program writes data through the output stream, it only means that the program submits a batch of data to the network, and the network is responsible for sending it to the receiver // Tips: When the program closes the Socket, it is possible that the batch of data is still transmitted on the network and has not reached the receiver // Tips: The "remained remaining data" mentioned here refers to this data that is still transmitted on the network and has not been received by the receiver this.connection.setSoLinger(true, 5);// Indicates the size of the buffer where the data is sent this.connection.sesendBuffeSize (1024); // indique la taille du tampon où les données sont reçues ce.connection.SetReceiveBuffeSize (1024); // indique la taille du tampon où les données sont reçues. Ne vous transmettez pas les données)? Vrai est oui // sa valeur par défaut est fausse, ce qui signifie que TCP ne surveillera pas si la connexion est valide, et les clients inactifs peuvent exister en permanence sans préavis que le serveur a écrasé ce.connection.Setkevealive (true); // indique s'il prend en charge l'envoi d'un octet de données d'urgence TCP. Socket.SendurgentData (données) est utilisé pour envoyer un octet de données d'urgence TCP // Il est par défaut à False, c'est-à-dire que le récepteur ne fait aucun traitement lors de la réception des données d'urgence et les élimine directement. Si l'utilisateur souhaite envoyer des données d'urgence, elle doit être définie sur true // Après le réglage sur true, le récepteur mettra les données d'urgence reçues dans la même file d'attente que les données normales this.connection.setoobinline (true); // Cette méthode est utilisée pour définir le type de service. Le code suivant demande une haute fiabilité et un service de transmission de retard minimum (bits ou opérations de 0x04 et 0x10) // La classe de socket utilise 4 entiers pour représenter le type de service // 0x02: le faible coût (le bit de l'avant-dernier binaire est 1) // 0x04: une fiabilité élevée (le binaire binaire est 1) //0x08: 0x10: délai minimum (le cinquième avant-dernier bit binaire est 1) this.connection.setTrafficClass (0x04 | 0x10); // cette méthode est utilisée pour définir l'importance relative du temps de connexion, du retard et de la bande passante (les trois paramètres de cette méthode représentent trois indicateurs de données de transmission de réseau) // paramètre de connexion pour établir une connexion avec une connexion avec le temps minimum // latence ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- url.getPath () + "http / 1.1 /r/n") ;//if(url.getport()<0 || url.getport ()> 65536) {sb.append ("hôte:"). APPEND (url.gethost ()). APPEND ("/ r / n");} else {sb.append ("host:"). Host ()). APPEND (":"). APPEND (url.getport ()). Append ("/ r / n");} sb.append ("Connexion: keep-alive / r / n"); sb.append ("date: fri, 22 avril 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 & mot de passe = 123456 ".getBytes (" utf-8 "). Length) .Apnd (" / r / n "); sb.append (" / r / n "); this.connection.getOutputStream (). Write (sb.toString (). Disconnect () lève ioException {if (connected) {this.connection.close (); this.conned = false;}}} Ici, la définition du protocole est terminée.
Notre code de test est le suivant
Essayez de vous connecter à Oschina: // localhost: 8080 / test / ios.php
Url.setUrlStreamHandlerFactory (new eChourlStreamHandlerFactory ()); // urlconnection.setContentHandlerFactory (New EchocontentHandlerFactory ()); url url = new url ("oschina: // localhost: 8080 / test / oos.php"); connection = (eChourlConnection) url.openconnection (); connection.setDoOutput (true); connection.setDoInput (true); Printwriter pw = new printwriter (new OutputStreamWriter (connection.getOutputStream ())); pw.write ("name = zhangsan & mot de passe = 123456"); pw.flush (); InputStream Stream = Connection.getInputStream (); int len = -1; octet [] buf = nouveau octet [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) {// Le serveur renvoie un encodage à chunk, / r / n0 / r / n / r / n signifie que la lecture a terminé, analyse d'encodage chunché: http://dbscx.iteye.com/blog/830644 line = line. line.length () - "/ r / n0 / r / n / r / n" .length ()); System.out.println (ligne); casser; } else {System.out.println (ligne); }} pw.close (); Stream.Close ();Résultats en cours d'exécution
Le résultat montre que le protocole a en effet été défini avec succès
Bien sûr, l'analyse des données ci-dessus ne répond pas à nos exigences car elle est en train de coder des informations. Comment l'analyser répond aux exigences, veuillez bouger :
HTTP a vanté des données en codage et en algorithme d'analyse
5. Plus tard, l'analyseur de mineype personnalisé
ContentHandlerFactory est fourni en Java pour analyser Minetype. Nous formulons notre propre analyseur ici. Bien sûr, le JDK fournit plus abondamment. Ce que nous faisons ici, c'est répondre aux besoins spéciaux.
classe publique EchoContentHandler étend ContentHandler {public objet getContent (UrlConnection Connection) lève IOException {InputStream dans = Connection.getInputStream (); BuffereDreder Br = new Buffereader (New InputStreamReader (in)); Retour Br.readline ();} public objet GetContent (urlConnection {InputStream dans = 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;}}L'utilisation est très simple
UrlConnection.setContentHandlerFactory (new eChoContentHandlerFactory ());