Сокеты Java и выделенные соединения

Что состоит в том, чтобы обнаружить самый соответствующий путь, если сокет был отброшен или нет? Или ли пакет действительно на самом деле становился отправленным?

У меня есть библиотека для отправки Уведомлений о Нажатии Apple iPhone через Apple gatways (доступный на GitHub). Клиенты должны открыть сокет и отправить двоичное представление каждого сообщения; но к сожалению Apple не возвращает подтверждения вообще. Соединение может быть снова использовано для отправки нескольких сообщений также. Я использую простые Сокетные соединения Java. Соответствующие нормы:

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 еще, не исчерпывается.

Существует ли способ, которым я могу сказать наверняка, вошел ли пакет на самом деле в сеть или нет? Я экспериментировал со следующими двумя решениями:

  1. Вставьте дополнительное socket.getInputStream().read() операция с тайм-аутом на 250 мс. Это вызывает операцию чтения, которая перестала работать, когда соединение было отброшено, но зависает иначе для 250 мс.

  2. установите размер буфера отправки TCP (например. Socket.setSendBufferSize()) к двоичному размеру сообщения.

Обе из работы методов, но они значительно ухудшают качество обслуживания; пропускная способность идет от 100 сообщения/секунда приблизительно к 10 сообщениям/секунда самое большее.

Какие-либо предложения?

ОБНОВЛЕНИЕ:

Оспариваемый несколькими ответами, подвергающими сомнению возможность описанного. Я создал тесты "единицы" из поведения, которое я описываю. Проверьте случаи единицы в Gist 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

13
задан notnoop 10 January 2010 в 21:56
поделиться

2 ответа

[

] Это не очень поможет вам, но технически оба предложенных вами решения неверны. OutputStream.flush() и любые другие вызовы API, о которых вы можете подумать, не будут делать того, что вам нужно.[

] [

]Единственный портативный и надежный способ определить, получен ли пакет экспертом - это ждать подтверждения от эксперта. Это подтверждение может быть либо реальным ответом, либо изящным завершением работы сокета. Конец истории - другого способа действительно нет, и это не Java-специфично - это фундаментальное сетевое программирование.[

] [

]Если это не постоянное соединение - то есть, если вы просто посылаете что-то, а затем закрываете соединение - то, как вы это делаете, вы поймаете все IOExceptions (любое из них указывает на ошибку) и выполняете грациозное закрытие сокета:[

] [
1. socket.shutdownOutput();
2. wait for inputStream.read() to return -1, indicating the peer has also shutdown its socket
]
17
ответ дан 1 December 2019 в 22:23
поделиться

Если вы отправляете информацию, используя протокол TCP / IP к Apple, вы должны получать подтверждение. Однако вы заявили:

Apple не возвращает никаких Подтверждение Whatsover

Что вы подразумеваете под этим? Таким образом, TCP / IP гарантирует доставку, поэтому приемник должен подтвердить квитанцию. Однако он не гарантирует, однако доставки будет иметь место.

Если вы отправляете уведомление на Apple, и вы разбите свое соединение до получения ACK, нет способа сказать, были ли вы успешно или нет, чтобы вы просто должны отправить его снова. При нажатии одной и той же информации дважды является проблемой или не обрабатывается правильно на устройстве, то есть проблема. Решение состоит в том, чтобы исправить обработку устройства дубликата Push-уведомлений: нет ничего, что вы не можете сделать на толкающей стороне.

Усознание / вопрос / вопрос

ОК. Первая часть того, что вы понимаете, это ваш ответ на вторую часть. Только пакеты, которые получили ACKS, были отправлены и получили должным образом. Я уверен, что мы могли бы подумать о какой-то очень сложной схеме отслеживания каждого отдельного пакета. На вашем конце вам просто нужно иметь дело с множеством неудач, которые могут возникнуть (в Java, если кто-либо из них возникает, вызывается исключение). Если нет исключения, данные, которые вы просто пытались отправить, отправляется гарантировано, гарантировано протоколом TCP / IP.

Есть ли ситуация, когда данные, по-видимому, «отправляются», но не гарантированно принимаются, где не поднимается исключение? Ответ должен быть нет.

@examples

Приятные примеры, это разъясняет вещи довольно немного. Я бы подумал, что ошибка будет брошена. В примере опубликована ошибка на второй записи, но не первым. Это интересное поведение ... И я не смог найти много информации, объясняющую, почему она ведет себя так. Это, однако, объясняет, почему мы должны разработать наши собственные протоколы уровня приложения для проверки доставки.

Похоже, вы правы, что без протокола для подтверждения их не гарантируют, что устройство Apple получит уведомление. Apple также только последнее сообщение очереди. Посмотрите немного на службе, я смог определить, что эта услуга больше для удобства для клиента, но не может быть использована для гарантии обслуживания и должна быть объединена с другими методами. Я прочитал это из следующего источника.

http://blog.boxedice.com/2009/07/10/how-to-build-an-apple-push-notification-provider-server-tutorial/

кажется, что ответ не на том, или нет, вы можете сказать наверняка. Вы можете использовать Sniffer Packet, как Wireshark, чтобы сказать, если он был отправлен, но это все еще не гарантирует, что он был получен и отправлен на устройство из-за характера обслуживания.

2
ответ дан 1 December 2019 в 22:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: