Безопасен ли поток PrintWriter для сокета Java? - PullRequest
9 голосов
/ 03 апреля 2009

Итак, у меня есть две темы.

Тема 1 управляет клиентскими подключениями. (Есть только один клиент и один сервер)
Я называю это моей серверной веткой.

Поток два управляет отправкой сообщений клиенту. Я называю это потоком моих сообщений.

Нить 1 отвечает, помимо прочего, периодически отправляя сердцебиение клиенту.

При программировании я исходил из того, что сокеты не были безопасны для потоков, но буферы были, и пока я использовал отдельные буферы для потоков сервера и процессора, я был бы в порядке.

Я также сделал предположение, что «PrintWriter» был аналогом буфера сокетов в Java.

В соответствии с этими предположениями я написал эту функцию, чтобы послать сердцебиение:

public void sendHeartBeat(){
        logger.info("Sending a hearbeat!");
        PrintWriter printWriter=null;
        try {
            printWriter = new PrintWriter(clientSocket.getOutputStream());
        } catch (IOException e) {
            logger.info(e.toString());
        }
        if(printWriter!=null){
            printWriter.print("HEARTBEAT#");
            printWriter.flush();
        }
    }

Другой поток, «процессорный», делает нечто подобное:

printWriter=new PrintWriter(theServer.getClientSocket().getOutputStream());

Таким образом, я бы создавал новый «буфер» каждый раз, когда хотел отправить сердцебиение, и мои сообщения никогда не были бы перезаписаны.

К сожалению, похоже, что это не так. И я получаю сообщение, поступающее через канал, как это: dsgdsbHEARTBEAT # SDG

Это вызывает дамп ядра позже.

Вот мои вопросы:

1) Разъемы, очевидно, не являются поточно-ориентированными, но действительно ли PrintWriters, которые я получаю от них, являются поточно-ориентированными? Или он просто возвращает тот же PrintWriter?

2) Что аналогично буферу сокетов в Java? Как я должен думать об этой проблеме?

3) Как сделать так, чтобы эти потоки не записывали в один и тот же буфер на сокете?

Ответы [ 2 ]

11 голосов
/ 03 апреля 2009

Плохой дизайн - иметь несколько PrintWriter в одном потоке. На самом деле вы хотите, чтобы по крайней мере объект, вызывающий их, был синхронизирован (или ограничен потоком).

Однако, если по какой-то причине вам нужно несколько PrintWriter s:

Первая проблема: Writer s не использует this в качестве блокировки. PrintWriter и BufferedWriter по умолчанию оба используют Writer, с которым они построены, в качестве блокировки. Это очевидно полностью сломано. Они должны использовать замок Writer, а не сам Writer. Простая ошибка, учитывая, что блокировка функции Object снимает защиту статического типа. Поэтому вам нужно создать PrintWriter с сокетом OutputStream (или другим обычным объектом) в качестве замка.

Во-вторых, у нас есть буферизация в PrintWriter. Итак, заканчивайте буфер, наполовину записывайтесь и наполовину ждите следующей записи. Чтобы предотвратить это, либо заблокируйте внешне, чтобы объединить print и flush, либо используйте автоматическую очистку и добавьте символ новой строки.

Итак, это не значимо поточно-ориентированный, но вы можете взломать его. Или вы можете использовать лучший дизайн.

4 голосов
/ 03 апреля 2009

Вам нужен способ использовать один и тот же PrintWriter между потоками (t1.writer == t2.writer, а не только PrintWriter s, созданный из того же OutputStream). При одинаковом PrintWriter все операции записи синхронизируются.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...