Java les prises et pertes de connexion

Quel est le moyen le plus approprié pour détecter si un socket a été abandonné ou pas? Ou si un paquet n'a en fait envoyé?

J'ai une bibliothèque pour l'envoi de Notifications Push d'Apple pour iphone sur l'Apple gatways (disponible sur GitHub). Les Clients ont besoin d'ouvrir un socket et de l'envoyer à une représentation binaire de chaque message; mais, malheureusement, Apple n'a pas de retour d'accusé de réception que ce soit. La connexion peut être réutilisé pour envoyer plusieurs messages. Je suis en utilisant le Java simple connexions Socket. Le code correspondant est:

Socket socket = socket();   //returns an reused open socket, or a new one
socket.getOutputStream().write(m.marshall());
socket.getOutputStream().flush();
logger.debug("Message \"{}\" sent", m);

Dans certains cas, si une connexion est abandonnée alors qu'un message est envoyé ou vers la droite avant; Socket.getOutputStream().write() se termine avec succès. Je m'attends c'est en raison de la fenêtre TCP n'est pas encore épuisé.

Est-il une manière que je peux dire pour sûr que si un paquet effectivement eu dans le réseau ou pas? J'ai testé les deux solutions suivantes:

  1. Insérer un socket.getInputStream().read() opération avec un 250ms délai d'attente. Cela oblige une opération de lecture qui échoue lorsque la connexion a été interrompue, mais se bloque sinon pour les 250ms.
  2. ensemble TCP envoi de taille de la mémoire tampon (par exemple,Socket.setSendBufferSize()) pour le message binaire de taille.

À la fois des méthodes de travail, mais ils dégradent considérablement la qualité du service; le débit va de 100 messages/seconde à environ 10 messages/seconde au plus.

Des suggestions?

Mise à JOUR:

Contestée par plusieurs réponses remettre en question la possibilité de le décrire. J'ai construit "l'unité" des tests de comportement que je décris. Découvrez l'unité des cas à Gist 273786.

À la fois les tests unitaires ont deux fils, un serveur et un client. Le serveur se ferme tandis que le client envoie des données sans une IOException jeté de toute façon. Ici est la principale méthode:

public static void main(String[] args) throws Throwable {
final int PORT = 8005;
final int FIRST_BUF_SIZE = 5;
final Throwable[] errors = new Throwable[1];
final Semaphore serverClosing = new Semaphore(0);
final Semaphore messageFlushed = new Semaphore(0);
class ServerThread extends Thread {
public void run() {
try {
ServerSocket ssocket = new ServerSocket(PORT);
Socket socket = ssocket.accept();
InputStream s = socket.getInputStream();
s.read(new byte[FIRST_BUF_SIZE]);
messageFlushed.acquire();
socket.close();
ssocket.close();
System.out.println("Closed socket");
serverClosing.release();
} catch (Throwable e) {
errors[0] = e;
}
}
}
class ClientThread extends Thread {
public void run() {
try {
Socket socket = new Socket("localhost", PORT);
OutputStream st = socket.getOutputStream();
st.write(new byte[FIRST_BUF_SIZE]);
st.flush();
messageFlushed.release();
serverClosing.acquire(1);
System.out.println("writing new packets");
//sending more packets while server already
//closed connection
st.write(32);
st.flush();
st.close();
System.out.println("Sent");
} catch (Throwable e) {
errors[0] = e;
}
}
}
Thread thread1 = new ServerThread();
Thread thread2 = new ClientThread();
thread1.start();
thread2.start();
thread1.join();
thread2.join();
if (errors[0] != null)
throw errors[0];
System.out.println("Run without any errors");
}

[D'ailleurs, j'ai aussi une simultanéité bibliothèque de test, qui fait l'installation de manière un peu plus précise et plus claire. La caisse de l'échantillon à gist ainsi].

Lors de l'exécution j'obtiens le résultat suivant:

Closed socket
writing new packets
Finished writing
Run without any errors
Mise à jour de réponse.
Comme je l'ai déjà indiqué dans ma réponse, si vous voulez être sûr qu'il n'y a aucune erreur, vous devez effectuer une gracieuse de fin de connexion. Exécuter shutdownOutput(), la lecture jusqu'à ce que vous recevez des expressions du FOLKLORE, puis fermer le socket. La drôle de fin de connexion est dans l'essence de la réception d'un accusé de pairs qu'il a reçu de vous OK, ce qui est exactement ce que vous voulez.

OriginalL'auteur notnoop | 2010-01-08