Java-сокеты и удаленные соединения
Какие'самый подходящий способ определить, был ли сокет удален или нет? Или пакет действительно был отправлен?
У меня есть библиотека для отправки Apple Push-уведомлений на iPhone через шлюзы Apple (доступно на GitHub). Клиенты должны открыть сокет и отправить двоичное представление каждого сообщения; но, к сожалению, Apple нене вернуть никакого подтверждения вообще. Соединение также можно использовать для отправки нескольких сообщений. Я'м с использованием простых соединений Java Socket. Соответствующий код:
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);
В некоторых случаях, если соединение прерывается во время отправки сообщения или прямо перед ним;Socket.getOutputStream().write()
успешно заканчивается, хотя. Я ожидаю этогоиз-за окна TCP неТ исчерпан.
Есть ли способ, которым я могу точно сказать, действительно ли пакет попал в сеть или нет? Я экспериментировал со следующими двумя решениями:
Вставьте дополнительныйsocket.getInputStream().read()
работа с тайм-аутом 250 мс. Это вызывает операцию чтения, которая завершается неудачно при разрыве соединения, но в противном случае зависает на 250 мс.
установить размер буфера отправки TCP (например,Socket.setSendBufferSize()
) к сообщению двоичный размер.
Оба метода работают, но они значительно ухудшают качество обслуживания; Пропускная способность составляет не более 100 сообщений в секунду и не более 10 сообщений в секунду.
Какие-либо предложения?
ОБНОВИТЬ:
Оспаривается множественные ответы, ставящие под сомнение возможность описанного. Я построилединица измерения" тесты поведения ям описания. Проверьте случаи блока вСуть 273786.
Оба модульных теста имеют два потока: сервер и клиент. Сервер закрывается, пока клиент отправляет данные без IOException в любом случае. Вот основной метод:
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");
}
[Между прочим, у меня также есть библиотека тестирования параллелизма, которая делает настройку немного лучше и понятнее. Оформить заказ образца также.
При запуске я получаю следующий вывод:
Closed socket
writing new packets
Finished writing
Run without any errors