Écoute des requêtes TCP et UDP sur le même port
j'écris un ensemble de programmes Client/Serveur
selon l'opération demandée par le client, j'utilise make TCP ou UDP request.
implémenter le côté client est simple, car je peux facilement ouvrir la connexion avec n'importe quel protocole et envoyer la requête au côté serveur.
côté serveur, d'un autre côté, je voudrais écouter à la fois les connexions UDP et TCP sur le même port. De plus, j'aime le serveur d'ouvrir nouveau thread pour chaque demande de connexion.
j'ai adopté l'approche a expliqué: texte du lien
j'ai étendu cet échantillon de code en créant de nouveaux threads pour chaque requête TCP/UDP.
cela fonctionne correctement si J'utilise TCP seulement, mais cela échoue quand je tente de faire des fixations UDP.
s'il vous Plaît me donner une suggestion comment puis-je corriger cela.
tnx
voici le code du serveur:
public class Server {
public static void main(String args[]) {
try {
int port = 4444;
if (args.length > 0)
port = Integer.parseInt(args[0]);
SocketAddress localport = new InetSocketAddress(port);
// Create and bind a tcp channel to listen for connections on.
ServerSocketChannel tcpserver = ServerSocketChannel.open();
tcpserver.socket().bind(localport);
// Also create and bind a DatagramChannel to listen on.
DatagramChannel udpserver = DatagramChannel.open();
udpserver.socket().bind(localport);
// Specify non-blocking mode for both channels, since our
// Selector object will be doing the blocking for us.
tcpserver.configureBlocking(false);
udpserver.configureBlocking(false);
// The Selector object is what allows us to block while waiting
// for activity on either of the two channels.
Selector selector = Selector.open();
tcpserver.register(selector, SelectionKey.OP_ACCEPT);
udpserver.register(selector, SelectionKey.OP_READ);
System.out.println("Server Sterted on port: " + port + "!");
//Load Map
Utils.LoadMap("mapa");
System.out.println("Server map ... LOADED!");
// Now loop forever, processing client connections
while(true) {
try {
selector.select();
Set<SelectionKey> keys = selector.selectedKeys();
// Iterate through the Set of keys.
for (Iterator<SelectionKey> i = keys.iterator(); i.hasNext();) {
SelectionKey key = i.next();
i.remove();
Channel c = key.channel();
if (key.isAcceptable() && c == tcpserver) {
new TCPThread(tcpserver.accept().socket()).start();
} else if (key.isReadable() && c == udpserver) {
new UDPThread(udpserver.socket()).start();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
System.err.println(e);
System.exit(1);
}
}
}
le code UDPThread:
public class UDPThread extends Thread {
private DatagramSocket socket = null;
public UDPThread(DatagramSocket socket) {
super("UDPThread");
this.socket = socket;
}
@Override
public void run() {
byte[] buffer = new byte[2048];
try {
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
socket.receive(packet);
String inputLine = new String(buffer);
String outputLine = Utils.processCommand(inputLine.trim());
DatagramPacket reply = new DatagramPacket(outputLine.getBytes(), outputLine.getBytes().length,
packet.getAddress(), packet.getPort());
socket.send(reply);
} catch (IOException e) {
e.printStackTrace();
}
socket.close();
}
}
je reçois:
Exception in thread "UDPThread" java.nio.channels.IllegalBlockingModeException
at sun.nio.ch.DatagramSocketAdaptor.receive(Unknown Source)
at server.UDPThread.run(UDPThread.java:25)
10x
3 réponses
ça devrait marcher. Un des problèmes avec ce code, semble-t-il, est que la taille des octets est fixée à 0, ce qui signifie que le datagramme est écarté (comme il est mentionné dans les commentaires). Si vous avez besoin de recevoir des informations sur UDP et que vous êtes sur un réseau fiable, vous pouvez définir la taille assez grande et recevoir de gros datagrammes constitués de paquets multiples. Sinon, sur un réseau non fiable, réglez ça à la taille MTU. Assurez-vous de retourner() le ByteBuffer après avoir reçu quelque chose dedans.
aussi, créer de nouveaux threads pour chaque requête est une mauvaise idée, créer un thread 'session' pour chaque IP différente que vous recevez dans une HashMap ou quelque chose, et puis faire un bloc gardé sur l'objet session. Réveillez le fil dormant sur cet objet lorsque vous recevez un message après avoir passé de nouvelles informations. Le code de sélection que vous avez est conçu pour éviter la création de threads de cette façon.
Edit: en se basant sur le code ci-dessus, vous créez un canal de datagramme et ensuite vous utilisez la socket pour recevoir des datagrammes directement? Qui n'a pas de sens. N'utilisez les méthodes de canal qu'après avoir relié le canal. Aussi, ne faites pas cela dans un fil séparé. Votre code n'est pas sûr et se déchaînera tout seul. Main les informations reçues hors de la session " thread comme mentionné plus haut. Le sélecteur est conçu pour vous indiquer quels canaux peuvent être lus sans blocage (bien que le blocage soit désactivé quoi qu'il en soit, il vous indiquera quels canaux ont des données à lire).
AFAIK, vous devriez être capable d'écouter à la fois les connexions TCP et les messages UDP sur le même port. Il serait utile si vous avez posté votre code UDP, et l'exception + stacktrace que vous voyez.
vous ne pouvez pas utiliser DatagramSocket.receive()
en mode non-blocage. Vous devez utiliser les méthodes read()
ou receive()
de votre DatagramChannel
directement.
en fait comme vous utilisez le mode non-bloquant et un Selector
, il est tout à fait impossible de voir pourquoi vous utilisez aussi un UDPThread
du tout. Il suffit d'appeler udpserver.receive()
au lieu de démarrer le fil.