Java - Concurrencia y Swing

   
Vista:

Concurrencia y Swing

Publicado por David (11 intervenciones) el 22/08/2011 15:40:53
Hola. Estoy simulando un chat para dos personas en Java. En lugar de sockets empleo pipes. La idea es crear dos GUI's simétricas, cada una de las cuales genera un thread Emisor y otro Receptor. El thread Emisor de una GUI se enlaza mediante una pipe al thread Receptor de la otra, y viceversa, el thread Receptor de la primera GUI se enlaza con una pipe al thread Emisor de la otra. El thread Emisor recibe por otra pipe los mensajes de la capa de presentación y los pone en la pipe que simula el socket, que está enlazada con la pipe correspondiente del Receptor. Antes de enviar un mensaje al Emisor, la capa de presentación lo escribe en un área de texto en pantalla. Cuando el Receptor recibe un mensaje por la pipe que simula el socket, lo envía a la capa de presentación por otra pipe y se escribe en el área de texto mencionada antes. La aplicación en sí es sencilla, pero aún así no funciona. Probablemente el error esté en el semáforo de mutex que sirve para que los mensajes no se mezclen al escribirlos en el área de texto. También puede ser que no permita crear dos GUI's independientes. No lo sé. El código es así:

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
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
/*
 * CapaPresentacioX2U1.java
 *
 * Created on 01-ago-2011, 22:04:42
 */
 
package xat2users;
 
import java.io.* ;
import java.util.concurrent.TimeUnit;
import javax.swing.* ;
 
/**
 *
 * @author David
 */
public class CapaPresentacioX2U1 extends JFrame {
    public PipedReader pr;
    public PipedWriter pw;
    public final Boolean mutex = false;
    public Boolean fi = false;
 
    /** Creates new form CapaPresentacioX2U1 */
    public CapaPresentacioX2U1(PipedReader prSocket, PipedWriter pwSocket, boolean mode) {
 
        initComponents();
 
        Emissor1 emissor = null;
        Receptor1 receptor = null;
 
        pr = new PipedReader(); // pipe de 'receptor' a CP.
        pw = new PipedWriter(); // pipe de CP a 'emissor'.
 
        // L'aplicació té dues finestres independents, i cadascuna 
        // genera dos fluxes, un emissor i un receptor, que s'associen 
        // a les pipes que passem com a paràmetres al constructor
        // de la classe.
        if (mode) {
            // En aquest cas, 'emissor' escriu a la pipe 'pwSocket'
            // i 'receptor' llegeix de la pipe 'prSocket'.
            emissor = new Emissor1(pwSocket, pw, fi);
            receptor = new Receptor1(prSocket, pr, fi, mutex);
            setTitle("Finestra 1");
        }
        else {
            // En l'altre cas possible, 'emissor' escriu a la pipe 'prSocket'
            // i 'receptor' llegeix de la pipe 'pwSocket'.
            try {
                emissor = new Emissor1(new PipedWriter(prSocket), pw, fi) ;
                receptor = new Receptor1(new PipedReader(pwSocket), pr, fi, mutex);
            }
            catch (IOException e) {
                System.err.println("Error en connectar pipes.");
                System.exit(1);
            }
            setTitle("Finestra 2");
        }
        // creem els threads:
        Thread t1 = new Thread(emissor);
        Thread t2 = new Thread(receptor);
 
        // iniciem els threads:
        t1.start();
        t2.start();
    }
 
    private void espera_activa_pipe_Receptor() {
        Transmissor tr = new Transmissor(); // creem un objecte
                // Transmissor per a usar la seva funció 'llegir'.
        while (!fi) {
            boolean exit = false;
            String s = null;
            while ((!exit) && (!fi)) {
                s = tr.llegir(pr);
                try {
                    if (s.equals("")) TimeUnit.MILLISECONDS.sleep(100);
                    else exit = true;
                }
                catch (InterruptedException e) {
                    System.err.println("Thread despertat mentre dormia.");
                }
            }
            if (exit) {
                synchronized(mutex) {
                    jTextArea1.append(s + "\n");
                }
            }
        }
    }
 
    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {
 
        jScrollPane1 = new javax.swing.JScrollPane();
        jTextArea1 = new javax.swing.JTextArea();
        jTextField1 = new javax.swing.JTextField();
 
        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowClosing(java.awt.event.WindowEvent evt) {
                formWindowClosing(evt);
            }
        });
 
        jTextArea1.setColumns(20);
        jTextArea1.setRows(5);
        jScrollPane1.setViewportView(jTextArea1);
 
        jTextField1.setText("jTextField1");
        jTextField1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jTextField1ActionPerformed(evt);
            }
        });
 
        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 380, Short.MAX_VALUE)
                    .addComponent(jTextField1, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 380, Short.MAX_VALUE))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 225, Short.MAX_VALUE)
                .addGap(18, 18, 18)
                .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(26, 26, 26))
        );
 
        pack();
    }// </editor-fold>                        
 
    private void jTextField1ActionPerformed(java.awt.event.ActionEvent evt) {
        String s = jTextField1.getText(); // agafem el text del camp de text.
        if (!s.equals("")) {  // si el text no és buit el posem a l'historial.
            synchronized(mutex) {
                jTextArea1.append(s + "\n");  // posem el text a l'historial.
                    // el proper text anirà a la línia següent de l'historial..
                try {
                    pw.write(s); // enviem text a l'emissor.
                }
                catch (IOException e) {
                    System.err.println("Error en escriure a pipe.");
                }
            }
        }
    }
 
    private void formWindowClosing(java.awt.event.WindowEvent evt) {
        fi = true;
        System.exit(0);
    }
 
    /**
    * @param args the command line arguments
    */
    public static void main(String args[]) {
        final PipedReader prSocket = new PipedReader();
        final PipedWriter pwSocket = new PipedWriter();
 
        // Primera finestra:
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                CapaPresentacioX2U1 cp = new CapaPresentacioX2U1(prSocket, pwSocket, false);
                cp.setVisible(true);
                cp.espera_activa_pipe_Receptor();
            }
        });
 
        // Segona finestra:
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                CapaPresentacioX2U1 cp = new CapaPresentacioX2U1(prSocket, pwSocket, true);
                cp.setVisible(true);
                cp.espera_activa_pipe_Receptor();
            }
        });
    }
 
    // Variables declaration - do not modify                     
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTextArea jTextArea1;
    private javax.swing.JTextField jTextField1;
    // End of variables declaration                   
 
}
 
/****************************************
 * $(name).java To change this template, choose Tools | Templates
 * $(name).java and open the template in the editor.
 **************************************/
 
package xat2users;
 
import java.io.* ;
 
/**
 *
 * @author David
 */
public class Emissor1 extends Transmissor implements Runnable {
 
    private Boolean fi;
    private PipedWriter pwSocket;  // simulador de socket.
    private PipedReader pr;
 
    /* Paràmetres:
     * pwSocket: pipe d'escriptura que simula socket de sortida.
     * pw : pipe d'escriptura que connecta amb la capa de presentació
     *      (llegirem d'ella per a aconseguir el missatge a enviar pel
     *      socket).
    */
    public Emissor1 (PipedWriter pwSocket, PipedWriter pw, Boolean fi) {
        this.pwSocket = pwSocket;
        this.fi = fi;
        try {
            pr = new PipedReader(pw); // 'pr' llegirà de 'pw'.
        }
        catch (IOException e) {
            System.err.println("Error en connectar pipe.");
            fi = true;
            System.exit(1);
        }
    }
 
    public void run () {
        while (!fi) {
            String s = llegir(pr);  // 'llegir' està definida a Transmissor.
            try {
                pwSocket.write(s);
            }
            catch (IOException e) {
                System.err.println("Error en escriure a la pipe.");
            }
        }
    }
}
 
/****************************************
 * $(name).java To change this template, choose Tools | Templates
 * $(name).java and open the template in the editor.
 **************************************/
 
package xat2users;
 
import java.io.* ;
import java.util.concurrent.TimeUnit;
 
/**
 *
 * @author David
 */
 
// Heretem de Transmissor per a heretar el mètode 'llegir', que s'usa
// tant a Emissor com a Receptor.
// Heretem de Runnable per a poder fer un thread.
class Receptor1 extends Transmissor implements Runnable {
 
    private PipedReader prSocket;  // Simula un socket.
    private PipedReader pr;
    private PipedWriter pw;
    private Boolean fi;
    private final Boolean mutex;
 
    /* Paràmetres:
     * prSocket: pipe de lectura que simula socket de entrada.
     * pr : pipe de lectura que connecta amb la capa de presentació
     *      (per a escriure a l'àrea de text d'historial de missatges).
    */
    public Receptor1 (PipedReader prSocket, PipedReader pr, Boolean fi, Boolean mutex) {
        super();
        this.prSocket = prSocket;
        this.fi = fi;
        this.mutex = mutex;
        try {
            pw = new PipedWriter(pr);
        }
        catch (IOException e) {
            System.err.println("Error en connectar pipe.");
            fi = true;  // per a què acabin la resta de threads.
            System.exit(1);
        }
    }
 
    public void run () {
        while (!fi) {
            String s = llegir_socket_fictici();
            try {
                synchronized(mutex) {
                    pw.write(s);
                }
            }
            catch (IOException e) {
                System.err.println("Error en escriure a pipe.");
            }
        }
    }
 
    private String llegir_socket_fictici( ) {
        String s = null;
        boolean exit = false;
        while ((!exit) && (!fi)) {
            s = llegir(prSocket);  // 'llegir' està definida a Transmissor.
            try {
                if (s.equals("")) TimeUnit.MILLISECONDS.sleep(100);
                else exit = true;
            }
            catch (InterruptedException e) {
                System.err.println("Thread despertat mentre dormia.");
            }
        }
        return s;
    }
}
 
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
 
package xat2users;
 
import java.io.* ;
 
/**
 *
 * @author David
 */
public class Transmissor {
 
    String llegir (PipedReader pr) {
        String s = "";
        boolean fi_pipe = false;
        boolean fi_linia = false;
        while ((!fi_pipe) && (!fi_linia)) {
            try {
                int b = pr.read();
                if ( b == -1) fi_pipe = true;
                else {
                    char ch = (char) b;
                    if ((ch == '\n') || (ch == '\r')) fi_linia = true;
                    else s = s + ch;
                }
            }
            catch (IOException e) {
                System.err.println("Error en llegir de pipe.");
            }
        }
        return s;
    }
}



Estaré muy agradecido a quien me ayude a encontrar el/los error/es en este código.
Valora esta pregunta
Me gusta: Está pregunta es útil y esta claraNo me gusta: Está pregunta no esta clara o no es útil
0
Responder