Различное поведение сокетов в Java-программах, работающих в Ubuntu или Windows - PullRequest
0 голосов
/ 24 июня 2010

Я работаю в области связи между двумя программами, одна на C ++, а другая на Java, подключенная через стандартные сокеты. Обе программы работают под UNIX (Ubuntu) на одной машине и регулярно обмениваются информацией в течение определенного периода времени. В какой-то момент выполнения и всегда в одной и той же точке он застревает, так как программа на C ++ отправляет информацию, а программа на Java не получает всю информацию, поэтому они блокируются, так как первый ожидает получить это, а второй не отправляет ничего, потому что не получил информацию в первую очередь.

Странно то, что вы запускаете программу на Java под Windows. Тогда все работает нормально, программа корректно завершается без каких-либо блокировок.

Я думаю, что это проблема с приложением Java, но почему разница между запуском под Ubuntu или Windows? Розетка ведет себя по-другому? Отличается ли какой-либо параметр от JVM в Ubuntu и Windows?

Заранее большое спасибо!

Julen.

EDIT:

Это код на стороне Java, который читает буфер:

   if (task.equals("receiving")){
        try {
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            out = socket.getOutputStream();

            // receive messages
            char[] length = new char[5];
            while (!socket.isClosed()&&(!socket.isInputShutdown())){
                in.read(length,0,5);
                // this way of reading the length implies that only one command
                // at a time can be received and interpreted, so far the iCS does not
                // concatenate more commands in one transmission
                int commandLength = length[4];
                System.err.println("Speed Advice --> command received with length "+ commandLength);
                char[] command = new char[commandLength - 1];
                in.read(command,0,commandLength - 1);
                /*if (cow){
                    System.err.println("Speed Advice --> Last byte received for X-pos is "+(int)command[commandLength-1]);
                }*/
                readCommand(command);
            }
            System.err.println("Speed Advice --> Socket was externally closed.");
            in.close();
            closeConnection();
        }catch (Exception e) {
            e.printStackTrace();
        }
    }

И эта C ++ отправляет информацию:

void 
    Socket::
    send( std::vector<unsigned char> b) 
    throw( SocketException )
{
    if( socket_ < 0 ) return;

    size_t numbytes = b.size();
    unsigned char *const buf = new unsigned char[numbytes];

    for(size_t i = 0; i < numbytes; ++i)
    {
        buf[i] = b[i];
    }

    if (verbose_) 
    {
        cerr << "Send " << numbytes << " bytes via tcpip::Socket: [";
        for(size_t i = 0; i < numbytes; ++i)
        {
            buf[i] = b[i];
            cerr << " " << (int)b[i] << " ";
        }
        cerr << "]" << endl;
    }

    unsigned char const *buf_ptr = buf;
    while( numbytes > 0 )
    {
#ifdef WIN32
        int n = ::send( socket_, (const char*)buf_ptr, static_cast<int>(numbytes), 0 );
#else
        int n = ::send( socket_, buf_ptr, numbytes, 0 );
#endif
        if( n<0 )
        {
            // BailOnSocketError definitely throws an exception so clear up heap
            delete[] buf;
            BailOnSocketError( "send failed" );
        }

        numbytes -= n;
        buf_ptr += n;
    }

    delete[] buf;
}

Ответы [ 4 ]

2 голосов
/ 25 июня 2010

BufferedReader не является проблемой конкретно и не является «стеком TCP [заполненным] заполненным».И select() не требуется для ее решения.

Вы делаете несколько типичных ошибок здесь.

  1. Вы игнорируете возвращаемое значение read(). Это можетбыть -1, указывая, что узел закрыл соединение, которое вы должны проверить и действовать в первую очередь.Или это может быть любое значение от 1 до запрашиваемого вами размера.Вы просто слепо предполагаете, что получите 5 байтов при вызове in.read(buffer,0,5).. На это нет никаких гарантий.Вам нужно использовать DataInputStream.readFully().

  2. Вы отправляете 8-битные символы из C ++ и используете Reader в Java.Это не имеет никакого смысла вообще.Используйте InputStream. В частности, DataInputStream so you can call readFully(), как предложено выше.

  3. Socket.isClosed() сообщает вам, вы закрыли сокет.Он не говорит вам, закрыл ли узел одноранговое соединение.Вот для чего указано выше -1. ​​

  4. Точно так же Socket.isInputShutdown() сообщает вам, есть ли у you вход для отключения на этом сокете.Это не говорит вам, есть ли у пира выход выключения на его конце.Опять же, это то, для чего указано выше -1. ​​

Таким образом, оба этих теста бессмысленны, и сообщение, которое вы печатаете, когда один из них является истинным, неверно.

1 голос
/ 24 июня 2010

Хотя BufferedReader отлично подходит для файловых операций, мне кажется очень плохой идеей использовать его при чтении из Socket.

В противном случае, возможно, BufferedReader считает, чтоданные по-прежнему поступают в буфер, хотя на самом деле это не так.

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

1 голос
/ 24 июня 2010

Проверьте связь с помощью сниффера.Wireshark хороший.

0 голосов
/ 24 июня 2010

Обратите внимание, что большие куски данных могут быть разделены на несколько пакетов при отправке через сокеты.Я написал ответ здесь о сокетах в C ++, в котором он скоро будет рассмотрен.

Я вижу три варианта:

  • Ваш стек TCP может быть переполнен.Это настоящий подонок.Вы можете прочитать больше об этом в этой статье , но вкратце: сокет заполнен на каком-то конце вашего сокета, что делает блок отправителя больше записей.Вам нужно будет прочитать эти данные с принимающей стороны, прежде чем send разблокируется.Вы можете проверить «TCP ZeroWindow» с помощью wireshark, чтобы найти это.(настройки по умолчанию будут черными с красным текстом, вы не можете пропустить его)
  • Возможно, отправляющая сторона ожидает вас , чтобы отправить больше данных для отправки
  • Я не думаю, что это действительно, но я полагаю, что принимающая сторона могла бы также ожидать получения большего количества данных.Насколько я понимаю, именно исходная сеть должна решить, следует ли отправлять данные или нет.

Вы можете использовать выбрать (извините, не знаюUnix-эквивалентные аргументы, или java) при отправке данных, чтобы проверить, можете ли вы действительно отправлять (также описано в моем ответе здесь ).

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