Java Réseau: Expliquer InputStream et OutputStream dans le support
J'ai créé un serveur en utilisant ServerSocket
. Après cela, j'ai créé Client à l'aide de Socket
, et de se connecter à ce serveur.
Après, je ne "quelques trucs" avec InputStream et OutputStream est prise de Prise de l'Objet. Mais, je ne comprends pas vraiment inputStream et outputStream tellement. Voici mon code simple :
private Socket sock = null;
private InputStream sockInput = null;
private OutputStream sockOutput = null;
...
String msg = "Hello World";
byte[] buffer = null;
try {
sockOutput.write(msg.getBytes(), 0, test.length());
sockOutput.write("Hello StackOverFlow".getBytes(), 0, test.length());
buffer = new byte[test.length()];
sockInput.read(buffer, 0, test.length());
System.out.println(new String(buffer));
sockInput.read(buffer, 0, test.length());
System.out.println(new String(buffer));
} catch (IOException e1) {
e1.printStackTrace();
}
Le résultat sera : "Hello World" et "Bonjour StackOverFlow".
Ici est côté serveur code :
private int serverPort = 0;
private ServerSocket serverSock = null;
public VerySimpleServer(int serverPort) {
this.serverPort = serverPort;
try {
serverSock = new ServerSocket(this.serverPort);
}
catch (IOException e){
e.printStackTrace(System.err);
}
}
//All this method does is wait for some bytes from the
//connection, read them, then write them back again, until the
//socket is closed from the other side.
public void handleConnection(InputStream sockInput, OutputStream sockOutput) {
while(true) {
byte[] buf=new byte[1024];
int bytes_read = 0;
try {
//This call to read() will wait forever, until the
//program on the other side either sends some data,
//or closes the socket.
bytes_read = sockInput.read(buf, 0, buf.length);
//If the socket is closed, sockInput.read() will return -1.
if(bytes_read < 0) {
System.err.println("Server: Tried to read from socket, read() returned < 0, Closing socket.");
return;
}
System.err.println("Server: Received "+bytes_read
+" bytes, sending them back to client, data="
+(new String(buf, 0, bytes_read)));
sockOutput.write(buf, 0, bytes_read);
//This call to flush() is optional - we're saying go
//ahead and send the data now instead of buffering
//it.
sockOutput.flush();
}
catch (Exception e){
System.err.println("Exception reading from/writing to socket, e="+e);
e.printStackTrace(System.err);
return;
}
}
}
public void waitForConnections() {
Socket sock = null;
InputStream sockInput = null;
OutputStream sockOutput = null;
while (true) {
try {
//This method call, accept(), blocks and waits
//(forever if necessary) until some other program
//opens a socket connection to our server. When some
//other program opens a connection to our server,
//accept() creates a new socket to represent that
//connection and returns.
sock = serverSock.accept();
System.err.println("Server : Have accepted new socket.");
//From this point on, no new socket connections can
//be made to our server until we call accept() again.
sockInput = sock.getInputStream();
sockOutput = sock.getOutputStream();
}
catch (IOException e){
e.printStackTrace(System.err);
}
//Do something with the socket - read bytes from the
//socket and write them back to the socket until the
//other side closes the connection.
handleConnection(sockInput, sockOutput);
//Now we close the socket.
try {
System.err.println("Closing socket.");
sock.close();
}
catch (Exception e){
System.err.println("Exception while closing socket.");
e.printStackTrace(System.err);
}
System.err.println("Finished with socket, waiting for next connection.");
}
}
public static void main(String argv[]) {
int port = 54321;
VerySimpleServer server = new VerySimpleServer(port);
server.waitForConnections();
}
Ma question est :
-
Lorsque j'utilise
sockOutput.write
et je peux revenir ces message parsockInput.read
. Ce message a été enregistré, à droite? Si ce vrai, est-il enregistré sur le Serveur, j'ai créé, ou tout simplement sauvé en quelque chose d'autre commeSocket Object
. -
Si j'ai écrit à la prise de Chaîne A1, A2,... an, donc je vais recevoir A1, A2, ... Une Chaîne respectivement, à droite?
Il ne le sauve pas, pourquoi voulez-vous savoir? Essayez d'écrire A1, A2 et de lire et de voir celui qui vient en premier.
J'ai posé cette question parce que, pourquoi je peux prendre à nouveau tableau d'octets lorsque j'utilise le flux d'entrée écrire à douille.
En supposant que votre serveur est simplement renvoyer les données, vos messages sont mis en mémoire par la mise en réseau des couches, attendre pour vous appeler
InputStream.read()
. Où précisément tous que les données sont à tout point dans le temps est une question complexe; tous ces détails, est prélevée à l'écart par les bibliothèques et de la pile réseau.Donc, cela veut dire : il dépend côté Serveur ? J'ai ajouter un serveur côté code, merci de le signaler pour moi. Merci 🙂
OriginalL'auteur hqt | 2012-10-03
Vous devez vous connecter pour publier un commentaire.
Un socket est une abstraction que vous utilisez pour parler de quelque chose sur le réseau. Voir le diagramme ci-dessous...
En Java, pour envoyer des données via la prise, vous obtenez une
OutputStream
(1), et d'écrire à laOutputStream
(sortie des données).De lire des données à partir de la douille, vous obtenez son
InputStream
, et de lire l'entrée de ce deuxième volet.Vous pouvez penser de la flux, une paire de d'une manière tuyaux connecté à une prise murale. Ce qui se passe de l'autre côté du mur n'est pas votre problème!
Dans votre cas, le serveur a un autre support (l'autre extrémité de la connexion), et l'autre paire de flux. Il utilise ses
InputStream
(2) pour lire à partir du réseau, et sesOutputStream
(3) pour l'écriture de la même données à travers le réseau de votre client, qui se lit à nouveau par l'intermédiaire de sonInputStream
(4) fin de l'aller-retour.Mise à jour: en réponse au commentaire:
Noter que les ruisseaux et les sockets juste envoyer des octets brutes; ils n'ont pas de notion de "message" à ce niveau d'abstraction. Donc, si vous envoyez X octets et un autre X octets, puis de lire X octets et de lire un autre X octets, alors le système se comporte comme si il y a deux messages, parce que c'est la façon dont vous avez divisé les octets.
Si vous envoyez X octets, et un autre X octets, puis de lire une réponse de longueur 2X, alors vous pourrait être en mesure de lire un seul combiné "message", mais comme vous l'avez remarqué, le sous-tendent la mise en œuvre des volets peuvent choisir de livrer des flots d'octets, de sorte qu'il peut retourner X octets, alors X octets, plus tard, ou 2 à la fois, ou 0,5 X quatre fois...
pourquoi le serveur ne peut le faire. Dans le code serveur ci-dessus, juste cette ligne :
sockOutput.write(buf, 0, bytes_read);
. Veuillez expliquer pour moi, merci 🙂Cela dépend de comment vous lire et à écrire. Vous êtes à la lecture (et l'écriture) d'un montant fixe de données (
test.length()
octets sur le côté client, et 1024 octets sur le côté serveur), ce qui peut ou ne peut pas couper vos données dans deux messages. Si vous écrire deux messages de longueur X, puis de lire une réponse de longueur 2X, alors vous pourriez lire un combiné unique message.Je pense que 1024 juste réinitialiser la condition de tableau d'octets. après cela, il suffit d'écrire des données est égale à la taille avec bytes_read. Par ailleurs, je pense que lors de l'utilisation de inputstream deuxième fois, je dois recevoir la valeur null.
OK, je vois, mais voir la documentation pour InputStream - c'est à l'implémentation sous-jacente lorsque vous donner quelques données, qui dans votre cas est probablement quand un paquet arrive (votre premier write())...
OriginalL'auteur DNA
InputStream
etOutputStream
sont deux choses complètement distinctes. Ce que vous écrivez dans un n'a pas de a priori rapport à ce que vous lisez à partir de l'autre. LeInputStream
vous donne toutes les données, le serveur décide de l'envoyer à vous. Je voudrais aussi faire des commentaires sur ce morceau de code:Vous utilisez la longueur d'une chaîne
test
(pas indiqué dans votre code), qui n'a rien à voir avec le tableau d'octets vous êtes de passage comme premier argument. Cela peut provoquer uneArrayIndexOutOfBoundsException
ou de troncature de votre message.Des commentaires à vos questions à jour
De l'examen de votre code côté serveur, c'est pas tout à fait correctement écrit. Vous avez besoin d'avoir
try { handleConnection(...); } finally { socket.close(); }
pour assurer un bon nettoyage après une erreur, ainsi que lors de l'achèvement normalement. Votre code ne ferme jamais quoi que ce soit sur le côté serveur.Enfin, et de manière plus critique, l'ensemble de votre code est écrit d'une manière qui peut entraîner un blocage. Normalement, vous avez besoin d'un thread séparé à lire et à écrire; sinon, les suivants peuvent se produire:
Pourquoi devrions-nous fermer la socket dans HanldeConnection() la méthode ? Parce qu'à waitforConnection(), j'ai déjà fermé. Cette façon de mal ? S'il vous plaît dites-moi. Merci 🙂
La règle est de toujours proche,
try-finally
. La façon dont vous le faites, il n'y a aucune garantie quesock.close()
sera atteint parce que vous attraperException
et pas tous lesThrowable
s. Même alors, l'approche est fausse à partir d'un autre point de vue, c'est que vous êtes la capture de l'Excepton trop tôt et réaliste code, il serait le mauvais endroit pour le gérer. Il est tolérable pour l'apprentissage du code, je suppose.OriginalL'auteur Marko Topolnik