Должен ли я синхронизировать socket.send? - PullRequest
4 голосов
/ 28 марта 2012

У меня есть 2 класса, где у меня есть один, чтобы отправлять команды в сокет, другой, который получает (и иногда отвечает на команды).

Должен ли я синхронизировать это? Или это не обязательно?

Оба класса работают в своих собственных потоках с объектом сокета, передаваемым каждому из них в качестве аргумента при thread.start();

Это правильный способ сделать это или я мог бы сделать что-то более эффективное?

Может ли это привести к ошибкам? Отправляющая часть:

    public void run(){
        send_chatline("roomf");

        int vvv = 0;
        while (this.socket.isConnected()){
            try{
                Thread.sleep(10000);
                vvv++;

                Thread.sleep(10000);
                send_chatline("alive");

                Thread.sleep(10000);

                if (vvv == 1) {
                    this.socket.flush();
                    this.socket.send("T,-1," + this.playerid * 3);
                    this.socket.flush();
                }
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

Но помни! Класс recieveFromSock также пишет иногда, когда появляются определенные команды.

Единственная функция sendTosock - поддерживать соединение (возможность оставаться в сети).

Ответы [ 4 ]

2 голосов
/ 28 марта 2012

Единственная гарантия, которую вы имеете, состоит в том, что отправленный байт отправляется один раз, а чтение байта читается один раз. Другие могут сказать, что о синхронизации заботится библиотека времени выполнения или основная операционная система. Любое такое утверждение зависит от реализации во время выполнения и / или от операционной системы (и, на мой взгляд, должно игнорироваться).

Итак, если у вас есть один поток, читающий из сокета, и один поток, записывающий в сокет, у вас все будет в порядке без синхронизации.

Если более чем один поток может записать в сокет, вы должны синхронизировать их действия, чтобы убедиться, что выходные данные, отправленные из двух потоков, не чередуются.

То же самое относится, если два потока читают из сокета. Вы должны синхронизировать чтения, чтобы убедиться, что данные, прочитанные одним потоком, не имеют «пробелов» из-за чтения другого потока.

Аналогичный вопрос, тот же вывод:

1 голос
/ 28 марта 2012

Синхронизация не требуется, поскольку синхронизация выполняется в сокете.Вопрос в том, взаимодействуют ли два класса / потока через сокеты, живущие в одной и той же JVM?Если это так, есть несколько более эффективных опций, самый простой из которых - BlockingQueue , где класс отправителя добавляет своих команд, а получатель принимает их.

1 голос
/ 28 марта 2012

Нужно ли синхронизировать это?

Нет.SocketImpl имеет собственную внутреннюю синхронизацию.Вы не удивитесь, узнав, что отправка не синхронизирована, а получение происходит.

0 голосов
/ 12 апреля 2012

Мне тоже было любопытно, что классы nio синхронизированы (только для nio). Просто посмотрите на метод записи здесь, на солнце JVM код

http://www.docjar.com/html/api/sun/nio/ch/SocketChannelImpl.java.html

Проверка старого кода сокета ввода-вывода, однако, показывает отсутствие синхронизации, хотя есть acquFD и releaseFD ... но нет синхронизации там ... которая, по-видимому, предотвращает закрытие, пока не будут выполнены все записи во всех потоках ( они предполагают, что записи из нескольких потоков подходят для каждой ОС ... но я не знаю, правда ли это, ИЛИ они синхронизируются в собственном коде JVM, поэтому разработчик знает, что они могут это сделать) .... нам нужна JVM Разработчик, чтобы сообщить нам, есть ли блок синхронизации в Windows JVM, Linux JVM и Mac JVM, и т. д. и т. д ....

private void socketWrite(byte b[], int off, int len) throws IOException {

    if (len <= 0 || off < 0 || off + len > b.length) {
        if (len == 0) {
            return;
        }
        throw new ArrayIndexOutOfBoundsException();
    }

    FileDescriptor fd = impl.acquireFD();
    try {
        socketWrite0(fd, b, off, len);
    } catch (SocketException se) {
        if (se instanceof sun.net.ConnectionResetException) {
            impl.setConnectionResetPending();
            se = new SocketException("Connection reset");
        }
        if (impl.isClosedOrPending()) {
            throw new SocketException("Socket closed");
        } else {
            throw se;
        }
    } finally {
        impl.releaseFD();
    }
} 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...