Newsgroup: it.comp.java
Titolo: porte multiple tcp e protocolli complessi

Ciao a tutti,
ho un problema con connessioni tcp.
-La mia applicazione simula diversi server tcp, in ascolto su diverse
porte.
 Come posso fare in modo che l'applicazione sia in ascolto sulla porta
x e sulla porta y nello stesso momento?
- Inoltre alcuni di questi server simulati, gestiscono protocolli di
comunicazione complessi, fatti di molti 'richiesta-risposta '. In un
ciclo while, il server e' in attesa finche' non riceve una richiesta da
parte del client, la processa, invia la risposta e si mette nuovamente
in ascolto di richieste.
Questo funziona correttamente solo con una sola 'richiesta-risposta'.
Se il client invia una nuova richiesta, il server pare non la riceva.
Premetto che io non chiudo stream e socket proprio perche' voglio
riutilizzare la stessa connessione.
Saluti
Palmis

Premetto che io non chiudo stream e socket proprio perche' voglio riutilizzare la stessa connessione.
Boh, bisognerebbe vedere un po' il codice....

ok per il suggerimento dei thread.
Ti mostro il codice.
Qui' non ho implementato i thread ma ho creato socket diversi per le
due connessioni. Pensi funzioni allo stesso modo?
package tcp;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import snmpManager.GetSetClassCommands;
//questa classe si pone in ascolto in attesa di comandi da parte di CCF
public class TCPServer {
	public static final int PORT_NLES = 10506;
	public static final int PORT_RIMS_A = 10027;
	public Socket socketNles;
	public Socket socketRimsA;
	public int obj;
	public int origin_address = 0;
	public int destination_address = 0;
	public int command_id = 0;
	public int command_type = 0;
	public int j = 0;
	/**
	 * Questo metodo effettua lo start della connessione e istanzia
eventuali
	 * stream che il socket utilizzerà.
	 *
	 * @throws IOException
	 *             se la connessione fallisce.
	 */
	public void start() throws IOException {
		// Crea il socket
		ServerSocket serverSocketNles = new ServerSocket(PORT_NLES);
		ServerSocket serverSocketRimsA = new ServerSocket(PORT_RIMS_A);
		// Ciclo infinito per ascolto del Client
		while (true) {
			System.out.println("NLES e' in attesa di chiamate dal Client... ");
			System.out.println("RIMS A e' in attesa di chiamate dal Client...
");
			// Attende sul serverSocket per contatti da parte del client
			socketNles = serverSocketNles.accept();
			socketRimsA = serverSocketRimsA.accept();
			// Stream di Byte usati per la comunicazione col socket
			DataInputStream inFromClientNles = new DataInputStream(socketNles
					.getInputStream());
			DataInputStream inFromClientRimsA = new DataInputStream(socketRimsA
					.getInputStream());
			// Effettua la lettura dello stream ricevuto dal client
			System.out.println("effettuo lettura Nles");
			for (int i = 1; i <= 7; i++) {
				obj = inFromClientNles.readUnsignedByte();
			}
			obj = inFromClientNles.readUnsignedShort();
			setOriginAddress(obj);
			obj = inFromClientNles.readUnsignedByte();
			obj = inFromClientNles.readUnsignedShort();
			setDestinationAddress(obj);
			for (int i = 1; i <= 42; i++) {
				obj = inFromClientNles.readUnsignedByte();
			}
			obj = inFromClientNles.readUnsignedByte();
			setCommandId(obj);
			obj = inFromClientNles.readUnsignedByte();
			setCommandType(obj);
			String[] valueNles = { Integer.toString(origin_address),
					Integer.toString(destination_address),
					Integer.toString(command_id),
					Integer.toString(command_type), Integer.toString(4) };
			System.out.println("j PRIMA" + j);
			GetSetClassCommands.setData(valueNles, j);
			if (socketNles.getInputStream() != null) {
				j++;
			} else {
			}
			System.out.println("j DOPO" + j);
			// Effettua la lettura dello stream ricevuto dal client
			System.out.println("effettuo lettura Rims A");
			for (int i = 1; i <= 7; i++) {
				obj = inFromClientRimsA.readUnsignedByte();
			}
			obj = inFromClientRimsA.readUnsignedShort();
			setOriginAddress(obj);
			obj = inFromClientRimsA.readUnsignedByte();
			obj = inFromClientRimsA.readUnsignedShort();
			setDestinationAddress(obj);
			for (int i = 1; i <= 42; i++) {
				obj = inFromClientRimsA.readUnsignedByte();
			}
			obj = inFromClientRimsA.readUnsignedByte();
			setCommandId(obj);
			obj = inFromClientRimsA.readUnsignedByte();
			setCommandType(obj);
			String[] valueRimsA = { Integer.toString(origin_address),
					Integer.toString(destination_address),
					Integer.toString(command_id),
					Integer.toString(command_type), Integer.toString(4) };
			System.out.println("j PRIMA" + j);
			GetSetClassCommands.setData(valueRimsA, j);
			if (socketRimsA.getInputStream() != null) {
				j++;
			} else {
			}
			System.out.println("j DOPO" + j);
		}
		// Fine del ciclo while, loop back e attende per un'altra connessione
		// col client
	}// Fine del metodo start()
	/**
	 * Questo metodo setta l'origin address del messaggio ricevuto,
prelevandolo
	 * dallo stream.
	 *
	 * @param oa
	 *            rappresenta l'origin address ricevuto.
	 */
	public void setOriginAddress(int oa) {
		origin_address = oa;
	}// Fine metodo setOriginAddress()
	/**
	 * Questo metodo setta il destination address del messaggio ricevuto,
	 * prelevandolo dallo stream.
	 *
	 * @param da
	 *            rappresenta il destination address ricevuto.
	 */
	public void setDestinationAddress(int da) {
		destination_address = da;
	}// Fine metodo setDestinationAddress()
	/**
	 * Questo metodo setta il command Id del messaggio ricevuto,
prelevandolo
	 * dallo stream.
	 *
	 * @param ci
	 *            rappresenta il command Id ricevuto.
	 */
	public void setCommandId(int ci) {
		command_id = ci;
	}// Fine metodo setCommandId()
	/**
	 * Questo metodo setta il command type del messaggio ricevuto,
prelevandolo
	 * dallo stream.
	 *
	 * @param ct
	 *            rappresenta il command type ricevuto.
	 */
	public void setCommandType(int ct) {
		command_type = ct;
	}// Fine metodo setCommandType()
	/**
	 * Questo metodo istanzia alcune classi e fa partire lo start().
	 */
	public static void TCP() throws Exception {
		TCPServer tcpServer = new TCPServer();
		System.out.println("PORTA " + PORT_NLES);
		System.out.println("PORTA " + PORT_RIMS_A);
		tcpServer.start();
	}// Fine del metodo TCP()
}// Fine della classe TCPServer

 due connessioni. Pensi funzioni allo stesso modo?
No.
Saluti
CarMas

Premetto che io non chiudo stream e socket proprio perche' voglio riutilizzare la stessa connessione.
Cosa mi dici in merito?
Grazie 
palmis

 Cosa mi dici in merito?
Che se fai:
while(true) {
   <accept>
   <apertura DataInputStream>
   <lettura dallo stream>
}
trovo perfettamente normale che legga una sola richiesta. Non vedo dove 
si aspetti o si metta in attesa di una successiva richiesta.
Saluti
CarMas

 writes:
p> ok per il suggerimento dei thread.
Peccato essere arrivati  tardi ma non mi ricordavo  il meccanismo e le
clasi implicate, purtroppo non ho mai dovuto risolvere quel problema.
I server per protocolli TCP/IP  che vedi in produzione e che accettano
connessioni  su varie porte  per vari  protocolli usano  una chiamata,
select()  se non  ricordo male,  che permette  loro di  usare  un solo
flusso  di  esecuzione  (thread,  task  a  seconda  della  granularità
consentita dal sistema) per stare in listen su più socket. La select()
ovviamente ritorna informazioni relative a quale dei socket "ha fatto
traffico" e da qui usualmente si crea un nuovo thread (o task, se non
c'è supporto per i thread) per gestire il servizio.
Un  occhiata al  terzo  volume de  "Internetworking  with TCP/IP"  può
tornare comodo.
Back to  Java. In Java la  cosa si fa attraverso  oggetti Selector nei
quali si  registrano i "selectable channels" (i  ServerSocket sono nel
giusto albero di eredità) che devono essere gestiti dal Selector.
Tanto di più purtroppo non posso dire perché non lo ho mai usato.
-- 
 /\            ___
/___/\__|_|\_|__|___Gian Uberto Lauri_____________________
  //--\ | | \|  |   Integralista GNUslamico  
\/		    e allevatore di bug da competizione

Grazie,
il tuo suggerimento è stato prezioso.
Pertanto ho creato due classi:
- una 'TCPParallelServer' attiva la socket e si pone in un ascolto
infinito del client;
- l'altra 'ServerThread'  extends Thread e viene istanziata appena
ricevo una chiamata dal client la processa e passa il controllo di
nuovo a 'TCPParallelServer' .
Adesso il protocollo funziona e va a buon fine, ma resta un problema.
Posso testare un sottosistema alla volta.
Vorrei invece che TCPParallelServer fosse in ascolto su piu' porte,
corrispondenti alla porte dei miei sottosistemi.
Per fare cio' devo fare in modo che TCPParallelServer estenda Runnable?
Grazie
Palmis

 writes:
p> Per fare cio' devo fare in modo che TCPParallelServer estenda
p> Runnable?
No, usare un Selector.


 Per fare cio' devo fare in modo che TCPParallelServer estenda Runnable?
Puo' essere una soluzione. Lanci tanti TCPParallelServer, ognuno in 
ascolto su una specifica porta.
Altrimenti segui il consiglio (che mi pare molto interessante) di Gian 
Umberto Lauri e prova a lavorare con i selectable channels, su cui pero' 
non ho mai messo le mani e non ti so aiutare.
Saluti
CarMas