7
votes

Comment créer une intrigue non bloquante Java d'une HTTPSURLConnection?

Fondamentalement, j'ai une URL qui diffuse des mises à jour XML à partir d'une salle de discussion lorsque de nouveaux messages sont affichés. J'aimerais transformer cette URL dans une intrigue d'intrigue et continuer à la lire tant que la connexion est maintenue et tant que je n'ai pas envoyé de fil.Interrupt (). Le problème que je connais est que BufferedReader.Ready () ne semble pas devenir vrai lorsqu'il y a du contenu à lire dans le flux.

J'utilise le code suivant: P>

BufferedReader buf = new BufferedReader(new InputStreamReader(ins));


String str = "";
while(Thread.interrupted() != true)
{
    connected = true;
    debug("Listening...");

    if(buf.ready())
    {
        debug("Something to be read.");
        if ((str = buf.readLine()) != null) {
            // str is one line of text; readLine() strips the newline character(s)
            urlContents += String.format("%s%n", str);
            urlContents = filter(urlContents);
        }
    }

    // Give the system a chance to buffer or interrupt.
    try{Thread.sleep(1000);} catch(Exception ee) {debug("Caught thread exception.");}
}


1 commentaires

Chaque connexion doit être divisée dans un fil séparé.


5 Réponses :


1
votes

Vous pouvez utiliser la bibliothèque Java Nio qui fournit des capacités d'E / S non bloquantes. Jetez un coup d'œil à cet article pour plus de détails et de l'exemple de code: http://www.drdobbs.com/java/184406242 .


2 commentaires

Cela ressemble à cela a les moyens que je cherchais à causer de temps à traiter les fils, enfreignant la connexion de blocage. Va essayer d'essayer. Merci.


Hmm. Je n'ai pas réussi à trouver un moyen d'interrompre correctement le fil bloqué à ce jour. Peut-être que je ne le fais tout simplement pas bien.



10
votes

Comment créer un Inpurstream

Vous ne pouvez pas. Votre question incarne une contradiciton en termes. Les flux en Java bloquent. Il n'y a donc rien de tel qu'un «code non bloquant introuvable '.

lecteur.Ready () retourne true lorsque les données peuvent être lues sans blocage. Point final. Inpurstreams et lecteurs bloque. Point final. Tout ici fonctionne comme conçu. Si vous souhaitez plus de concurrence avec ces API, vous devrez utiliser plusieurs threads. Ou socket.setsotimeout () et sa relation proche dans httpurlconnection .


5 commentaires

Je sais que je peux diviser les choses en fil ... Ce code est déjà dans son propre objet de thread (runnable). Ce que je veux, c'est savoir comment arrêter le fil en envoyant une sorte d'interruption. Lorsque le flux d'entrée attend que plus de données soient publiées dans le flux, il semble bloquer tout le reste, y compris le threadupts.


Pouvez-vous décrire une situation où Reader.Ready () serait capable de retourner vrai, si (comme vous l'avez dit) les lecteurs sont naturellement bloqués? Sur la base de ce que vous avez dit ci-dessus, il semblerait que le lecteur.Ready () est une méthode inutile.


Si les données sont déjà disponibles, Ready () renvoie true et un lecteur ne bloquera pas. Si aucune donnée n'est disponible, Ready () renvoie false et un lecteur bloquera.


Donc, si je sais qu'il y a des données disponibles dans le flux à lire, comment vient Buf.Ready () continue de retourner faux? C'est la partie qui me déroute. Je sais que des données sont prêtes à être lues dans le flux.


Vous ne pouvez pas savoir que cela. Seulement prêt () sait que (et Inverstream.Available (), dans les deux cas où le support). Il n'y a pas d'autre test. Pour certains flux tels que SSL n'est pris en charge, donc prêt () renvoie false et disponible () renvoie zéro. ASO Il existe une différence entre les données disponibles et une ligne complète étant disponible pour readline (), y compris la terminaison de ligne. readline () bloquera jusqu'à ce que tout cela arrive



6
votes

Pour NONBLOCKING IO N'utilisez pas d'intrustream et de lecteur (ou de sortie / écrivain), mais utilisez le java.nio. * classes, dans ce cas, un socketchanneau ( et un supplément d'un decodé de caractères).


Edit: comme réponse à votre commentaire:

cherche spécifiquement comment créer un canal de socket sur une URL HTTPS.

Les prises (et également Socketchaannels) fonctionnent sur la couche de transport (TCP), un (ou deux) niveau (s) sous (s) des protocoles de couche d'application tels que HTTP. Donc vous ne pouvez pas créer de canal de prise à une URL HTTPS .

Vous devez plutôt ouvrir un canal de prise sur le serveur de droite et le port droit (443 si rien d'autre donné dans l'URI), créez un SSLENGINE (dans JAVAX.NET.SSL) en mode client, puis lisez les données. du canal, l'alimentant au moteur SSL et l'inverse et envoyez / obtenez les bonnes lignes de protocole HTTP à / vers votre SSLengine, vérifiant toujours les valeurs de retour pour savoir combien d'octets étaient en fait traités et quel serait le prochaine étape à prendre.

Ce est assez compliqué ( Je l'ai fait une fois), et vous ne voulez pas vraiment faire cela si vous n'ayez pas implémenter un serveur avec de nombreux clients connectés en même temps (où vous ne pouvez pas avoir un seul fil pour chaque connexion). Au lieu de cela, Séjournez avec votre blocage d'introuvream qui lit de votre urlconnection et le mettez simplement dans un fil de rechange qui n'empêche pas le reste de votre application.


3 commentaires

Vous cherchez spécifiquement comment créer un canal de prise sur une URL HTTPS.


@Warkior: Consultez ma dernière modification - vous ne voulez pas vraiment faire cela.


Salut Paŭlo, merci pour le conseil. Cela a beaucoup de sens et répond à ma principale préoccupation de cette méthode particulière. Je n'ai vraiment aucun contrôle sur le serveur ... juste le client lisant du flux. Existe-t-il un moyen approprié de mettre fin à une connexion bloquée dans cette situation? Cela devra se produire si l'utilisateur change dans une nouvelle salle de discussion. (signifie que le système doit commencer à écouter un flux différent, terminant l'ancien auditeur)



0
votes

Il n'y a pas de mise en œuvre HTTP / HTTPS à l'aide de canaux. Il n'y a aucun moyen de lire l'intrigue d'une entrée d'une adresse httpurlconnaction de manière non bloquante. Vous devez utiliser une tierce partie liber ou implémenter http sur SocketCanNelel vous-même.


0 commentaires

-2
votes
import java.io.InputStream;
import java.util.Arrays;

/**
 * This code demonstrates non blocking read from standard input using separate
 * thread for reading.
 */
public class NonBlockingRead {

    // Holder for temporary store of read(InputStream is) value
    private static String threadValue = "";

    public static void main(String[] args) throws InterruptedException {

        NonBlockingRead test = new NonBlockingRead();

        while (true) {
            String tmp = test.read(System.in, 100);
            if (tmp.length() > 0)
                System.out.println(tmp);
            Thread.sleep(1000);
        }
    }

    /**
     * Non blocking read from input stream using controlled thread
     * 
     * @param is
     *            — InputStream to read
     * @param timeout
     *            — timeout, should not be less that 10
     * @return
     */
    String read(final InputStream is, int timeout) {

        // Start reading bytes from stream in separate thread
        Thread thread = new Thread() {

            public void run() {
                byte[] buffer = new byte[1024]; // read buffer
                byte[] readBytes = new byte[0]; // holder of actually read bytes
                try {
                    Thread.sleep(5);
                    // Read available bytes from stream
                    int size = is.read(buffer);
                    if (size > 0)
                        readBytes = Arrays.copyOf(buffer, size);
                    // and save read value in static variable
                    setValue(new String(readBytes, "UTF-8"));
                } catch (Exception e) {
                    System.err.println("Error reading input stream\nStack trace:\n" + e.getStackTrace());
                }
            }
        };
        thread.start(); // Start thread
        try {
            thread.join(timeout); // and join it with specified timeout
        } catch (InterruptedException e) {
            System.err.println("Data were note read in " + timeout + " ms");
        }
        return getValue();

    }

    private synchronized void setValue(String value) {
        threadValue = value;
    }

    private synchronized String getValue() {
        String tmp = new String(threadValue);
        setValue("");
        return tmp;
    }

}

3 commentaires

Ce n'est pas des E / S non bloquant. C'est un exemple futile et redondant de blocage d'E / S avec un délai d'attente, qui peut déjà être accompli via un délai de lecture et sockettimeoutException . Le code n'est clairement pas encore testé. INPUTStream.Lead (octet []) ne peut pas retourner zéro à moins que le tampon ne soit pas de zéro, ce qui n'est pas ici. Vous n'êtes pas testé pour la fin du flux, ni le communiquer à l'appelant d'origine. chaîne n'est pas un conteneur pour des données potentiellement binaires. La réponse est incorrecte dans tous les détails.


Merci d'erreurs de logique pointues. Je les ai corrigés. En général, ce code fait son but d'exécuter des tests d'unité dans les prises de serveur orientées texte. Si vous fournissez une solution plus élégante, je l'utiliserai volontiers.


Personne ne peut fournir de code pour un problème qui incarne une contradiction en termes.