IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Entrée/Sortie Java Discussion :

Soucis avec I/O tcp + thread


Sujet :

Entrée/Sortie Java

  1. #1
    Membre régulier
    Homme Profil pro
    Inscrit en
    Septembre 2006
    Messages
    64
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Septembre 2006
    Messages : 64
    Points : 85
    Points
    85
    Par défaut Soucis avec I/O tcp + thread
    Bonjour,
    j'ai un problème problème pour faire un simple ping-pong TCP avec un objet.
    En effet le client passe l'envoie de l'object et le serveur ne reçoit rien.
    Finalement j'ai décidé d'effectuer une abstraction supplémentaire : Channel.

    Mon test ne fonctionne toujours pas mais c'est plutôt à cause d'un blocage au niveau des Threads. Et là je sèche, j'arrive pas à savoir comment faire mon test.

    Channel :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    package common;
     
    import java.io.*;
    import java.net.ConnectException;
    import java.net.ServerSocket;
    import java.net.Socket;
     
    public class Channel {
        // This class implements a channel that can be written to and read
        // from by DirectoryServers, PeerServers and PeerClients.
     
        // The socket that is associated with this side of the Channel:
        Socket socket = null;
     
        // The streams in/out are used to read/write to/from the channel:
        ObjectInputStream in = null;
        ObjectOutputStream out = null;
     
        // Whether debugging messages should be displayed:
        boolean debuggingMessages = true;
     
     
        public Channel (ServerSocket serverSocket, boolean displayDebuggingMessages) throws ChannelException {
            // Calling this constructor signals that the caller wants to
            // wait for connections to the given port, alternatively pick
            // up a connection that is already waiting. The constructor
            // does not return until a connection is established. If there
            // is a problem, a ChannelException is thrown. This is usually
            // a fatal error and the program should be terminated.
     
            this.debuggingMessages = displayDebuggingMessages;
     
            try {
                if (displayDebuggingMessages) {
                    System.out.println("     Channel: waiting for somebody to connect ");
                }
     
                // Accept a connection, i.e. either pick up a waiting
                // connection or wait until somebody connects. Note that
                // the accept method blocks until a connection is
                // available.
                socket = serverSocket.accept();
     
                if (displayDebuggingMessages) {
                    System.out.println("     Channel: connection established");
                }
     
                // Set up the in/out streams for reading and writing:
                setupStreams();
     
            }
            catch (Exception e) {
                System.out.println("Channel: an error occurred while waiting for somebody to connect ");
                e.printStackTrace();
                ChannelException ce = new ChannelException(e);
                throw(ce);
            }
        }
     
     
        public Channel (String address, int portNumber, boolean displayDebuggingMessages)
            throws ConnectException, ChannelException {
            // Calling this constructor signals that the caller wants to
            // connect to the given address and port. It will wait until
            // the other side replies. If the connection is refused, a
            // java.net.ConnectException is thrown. This is usually not a
            // fatal error, so the program can continue if the exception
            // is caught by the calling method. If the connection cannot
            // be established for some other reason, a ChannelException is
            // thrown. This is usually a fatal error and the program
            // should be terminated.
     
            this.debuggingMessages = displayDebuggingMessages;
     
            try {
                if (displayDebuggingMessages) {
                    System.out.println("     Channel: establishing a connection to " +
                                       address + ", port " + portNumber);
                }
     
                // Create a connection, i.e. a socket, to the given
                // address and wait until there is a reply:
                socket = new Socket(address, portNumber);
     
                if (displayDebuggingMessages) {
                    System.out.println("     Channel: connection established");
                }
     
                // Set up the in/out streams for reading and writing:
                setupStreams();
     
            }
     
            catch (ConnectException e) {
                // The connection was refused. This is not necessarily a
                // fatal error so we throw the exception to the caller of
                // this method that can catch it and take some suitable
                // action.
                if (displayDebuggingMessages) {
                    System.out.println("     Channel: connection refused");
                }
                throw e;
            }
            catch (Exception e) {
                // Some other problem occurred while setting up the
                // connection. This is considered a fatal error and the
                // program is terminated.
                System.out.println("Channel: an error occurred while trying to connect to " +
                                   address + ", port " + portNumber);
                e.printStackTrace();
                ChannelException ce = new ChannelException(e);
                throw(ce);
            }
        }
     
     
        private void setupStreams () throws ChannelException {
            // This method is called when a socket has been established.
            // It sets up the in/out streams for the channel. If there is
            // a problem, a ChannelException is thrown. This is usually a
            // fatal error and the program should be terminated.
     
            try {
                // Get the general in/out streams that are already
                // associated with the socket:
                InputStream generalIn = socket.getInputStream();
                OutputStream generalOut = socket.getOutputStream();
     
                // We want to write bytes, ints, Strings and objects of
                // type Packet to the channel. The most appropriate filter
                // stream is thus Object.
     
                // Create the output stream first and flush it before
                // creating the input stream, otherwise the input
                // constructor may block (see API documentation). This is
                // necessary only for Object streams and does not apply
                // to, for example, Data streams.
     
                // Don't forget to let the objects written to the stream
                // implement java.io.Serializable.
     
                out = new ObjectOutputStream(generalOut);
                out.flush();
     
                in = new ObjectInputStream(generalIn);
            }
     
            catch (Exception e) {
                System.out.println("Channel: an error occurred while setting up the in/out streams.");
                e.printStackTrace();
                ChannelException ce = new ChannelException(e);
                throw(ce);
            }
        }
     
     
        public void sendObject (Object obj) throws ChannelException {
            // This method sends the given message over the channel as a
            // String. If there is a problem, e.g. if the connection is
            // closed by the other side, a ChannelException is thrown.
     
            if (debuggingMessages) {
                System.out.println("     Channel: sending Object");
            }
     
            try {
                out.writeObject(obj);
                out.flush();   // Don't forget to flush the output stream after writing!
            }
     
            catch (Exception e) {
                System.out.println("Channel: an error occurred while sending the message.");
                e.printStackTrace();
                ChannelException ce = new ChannelException(e);
                throw(ce);
            }
        }
     
     
        public Object receiveObject () throws ChannelException {
            // This method waits for a message in the form of a String and
            // returns it. If there is a problem, e.g. if the connection is
            // closed by the other side, a ChannelException is thrown.
     
            Object message = null;
            if (debuggingMessages) {
                System.out.println("     Channel: waiting for object...");
            }
     
            try {
                message = in.readObject();
            }
     
            catch (Exception e) {
                e.printStackTrace();
                ChannelException ce = new ChannelException(e);
                throw(ce);
            }
            if (debuggingMessages) {
                System.out.println("     Channel: received Object");
            }
            return message;
        }
     
     
        public void close() throws ChannelException {
            // This method closes the channel by closing the two in/out
            // streams and the two sockets. If there is a problem, a
            // ChannelException is thrown.
     
            try {
                in.close();
                out.close();
                socket.close();
            }
            catch (Exception e) {
                System.out.println("Channel: an error occurred while closing the channel.");
                e.printStackTrace();
                ChannelException ce = new ChannelException(e);
                throw(ce);
            }
        }
    }
    Le Test :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    package test;
     
    import java.io.IOException;
    import java.net.ConnectException;
    import java.net.ServerSocket;
     
    import common.Channel;
    import common.ChannelException;
     
    import junit.framework.TestCase;
     
    public class ChannelTest extends TestCase{
     
    	private class ServerThread implements Runnable{
    		private Channel chIn;
    		private ServerSocket server_;
    		public ServerThread() throws IOException{
     
    			server_ = new ServerSocket(9898);
    		}
     
    		@Override
    		public void run() {
    			chIn = new Channel(server_,true);
    			System.out.println("Server : Preparing to send");
    			String o = new String("HELLO");
    			chIn.sendObject(o);
    			String o1 = (String) chIn.receiveObject();
    			assertEquals(o1, o);
     
    		}
     
    	}
     
    	private class ClientThread implements Runnable{
    		private Channel chOut;
     
    		public ClientThread() throws ConnectException, ChannelException{
    			chOut = new Channel("127.0.0.1",9898,true);
    		}
     
    		@Override
    		public void run() {
    			Object o = chOut.receiveObject();
    			chOut.sendObject(o);
     
    		}
    	}
     
     
    	public ChannelTest(String name){
    		super(name);
    	}
    	public ChannelTest(){
    		super("ChannelTest");
    	}
     
    	public void testIO(){
    		try {
    			ServerThread sTh = new ServerThread();
    			ClientThread cTh = new ClientThread();
     
    			new Thread(sTh).start();
    			new Thread(cTh).start();
    		} catch (IOException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
     
     
     
     
    	}
     
    }

  2. #2
    Modérateur
    Avatar de nouknouk
    Homme Profil pro
    Inscrit en
    Décembre 2006
    Messages
    1 655
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 655
    Points : 2 161
    Points
    2 161
    Par défaut
    Salut,

    une idée comme ça, dans ServerThread.run() :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    chIn.sendObject(o);
    // peut-être ajouter un flush ici ???
    String o1 = (String) chIn.receiveObject();
    assertEquals(o1, o);
    Quelques autres idées en vrac:

    - implémenter un mécanisme de listener pour être prévenu lorsqu'un nouveau message est reçu (par exemple avec javax.swing.event.EventListener & EventListenerList) et remplacer dans les run() l'envoi/réception unique de ton object par une boucle while(isRunning) { ... }

    Il y a du tuto sur developpez.com pour les listeners, mais en quelques lignes, tu peux en implémenter un comme ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    public class MyClass {
        EventListenerList m_listeners = new EventListenerList();
     
        public static interface Listener extends EventListener {
            public void myEvent1(Object myParam1);
            public void myEvent2();
        }
     
        public void addListener(Listener l) {
            m_listeners.add(Listener.class, l);
        }
     
        public void removeListener(Listener l) {
            m_listeners.remove(Listener.class, l);
        }
    }
    pour émettre un événement depuis une fonction de MaClasse:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    public void myFunc() {
        for (Listener l : m_listeners.getListeners(Listener.class)) {
            l.myEvent1(new Object());
        }
    }
    Et un listener qui implémente l'interface:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    public class MyListenerClass extends MyClass.Listener {
        public void myEvent1(Object o) {
            // do something here...
        }
        public void myEvent2() {
            // do something here...
        }
     
    }
    Bien entendu, il ne faut pas oublier d'enregistrer le listener auprès de l'objet écouté:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    MyClass myClass = new MyClass();
    MyListenerClass l = new MyListenerClass();
    myClass.addListener(l);
    - autre chose: ne pas mettre la variable pour l'output du debug dans le constructeur de tes classes. Une solution plus 'propre' me semble d'utiliser une classe statique séparée (même si l'utilisation d'une classe statique n'est pas à proprement parler 'le plus propre qui soit' en règle générale). Par exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    public class MyLogger {
        private static boolean _isLogEnabled = true;
     
        public static setLogEnabled(boolean enabled) {
            _isLogEnabled = enabled;
        }
     
        public static printLog(String log) {
            if (_isLogEnabled) {
                System.out.println(log);
            }
        }
    }
     
    // ...et dans ton code, lorsque tu veux logger quelque chose:
    MyLogger.printLog("this is my log.");
    Mon projet du moment: BounceBox, un jeu multijoueurs sur Freebox, sur PC et depuis peu sur smartphone/tablette Android.

  3. #3
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    132
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mai 2007
    Messages : 132
    Points : 170
    Points
    170
    Par défaut
    Bonjour,

    le problème est que tu lis inputstream dans le constructeur de ton client et c'est ainsi que ton programme bloque dans le constructeur de ton client et donc la méthode run du serveur n'est jamais appelé ==> il n'envoie pas l'object ...

    tu devrais lire la doc sur ObjectInputStream

    Un moyen de simple de corriger le pb est de faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    chOut = new Channel("127.0.0.1",9898,true);
    Au niveau de la méthode run de ton clientthread et non dans le constructeur.

  4. #4
    Membre régulier
    Homme Profil pro
    Inscrit en
    Septembre 2006
    Messages
    64
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Septembre 2006
    Messages : 64
    Points : 85
    Points
    85
    Par défaut
    Bonjour, merci pour vos réponses.
    Je suis finalement revenu à mon ancien code sans class channel car là au moins les messages sont envoyés au client. Par contre le problème persiste pour le renvoie au server.
    Et un flush côté client lors du renvoie me donne:
    java.io.OptionalDataException (coté server thread)

    java.io.EOFException
    (côté client lors de la lecture suivante)

  5. #5
    Membre régulier
    Homme Profil pro
    Inscrit en
    Septembre 2006
    Messages
    64
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Septembre 2006
    Messages : 64
    Points : 85
    Points
    85
    Par défaut
    Hm... je crois que j'avais mis une bétise dans mon ancien code (avant que je fasse cette moche classe Channel).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    iStream = this.socket_.getInputStream();
    			oiStream = new ObjectInputStream(iStream);
    			oStream = new ObjectOutputStream(this.socket_.getOutputStream());
    			ooStream = new ObjectOutputStream(oStream);
    Double ObjectOutputStream... j'y ai vu que du feu.
    Enfin je crois que c'est ça parce que ça a l'air de marcher (mon repo SVN est mort pour l'instant donc impossible de checker les révisions). En tout cas y'a un peu plus d'activité côté wireshark (on voit que l'objet est envoyé cette fois...).

    Merci beaucoup pour votre aide.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Souci avec Thread::Sleep ()
    Par jlg_47 dans le forum C++/CLI
    Réponses: 3
    Dernier message: 20/02/2014, 14h34
  2. Soucis avec accept en tcp
    Par Jinn Thonik dans le forum Réseau
    Réponses: 11
    Dernier message: 07/04/2009, 14h56
  3. Soucis avec les threads
    Par f-k-z dans le forum C++
    Réponses: 12
    Dernier message: 15/01/2009, 16h33
  4. petit soucie avec POE ( Component::Pool::Thread )
    Par siaoly dans le forum Modules
    Réponses: 21
    Dernier message: 22/07/2006, 18h25
  5. Petit soucis avec Thread::Queue et une classe
    Par vodevil dans le forum Web
    Réponses: 16
    Dernier message: 09/06/2006, 21h41

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo