views:

91

answers:

4

Hello,

I am working in the communication between two programs, one in C++ and the other in Java, connected using standard sockets. Both programs run under UNIX (Ubuntu) within the same machine and share information for a period of time in regular basis. At some point of the execution and always at the same point it gets stuck since the program in C++ sends the information and the one in Java does not get all the info so they block since the first expect to receive that and the second is not sending anything because did not receive the information in the firs place.

The odd thing is one you execute the program in Java under Windows. Then it works fine, the program ends correctly without any blocing.

I think is an issue with the Java application but why the difference between running the under Ubuntu or Windows? Do the socket behave differently? Is some parameter different from the JVM in Ubuntu and Windows?

Thank you very much in advance!

Julen.

EDIT:

This the code in the Java side that reads the buffer:

   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();
        }
    }

And this C++ sending information:

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;
}
+1  A: 

Inspect the communication with a sniffer. Wireshark is a good one.

ninjalj
+2  A: 

While BufferedReader is great for file operations, it strikes me as a really bad idea to use one while reading from a Socket.

Otherwise, it might be that the BufferedReader thinks that data is still coming into the buffer when it really isn't.

I recommend removing it and dealing with the InputStreamReader directly to see if the problem still occurs.

R. Bemrose
Why exactly would using a BufferedReader over a Socket be a really bad idea? And how exactly might it be that 'the BufferedReader thinks that data is still coming into the buffer when it really isn't'? This is all nonsense, sorry.
EJP
@EJP: I haven't looked at the internal workings of `BufferedReader`, but buffering is for reading data that has a high retrieval cost, such as reading a large section from disk rather than one byte at a time. Sockets are coming in over the wire at a rate the receiver doesn't control. The `Socket` library already does its own buffering.
R. Bemrose
This is just more nonsense. The 'cost' of reading a socket consists of the context switch into the kernel, and reducing them via buffering has a marked effect on performance. Clearly you haven't tried it. And the Socket library *doesn't* do its own buffering. And you haven't answered my second question.
EJP
@EJP: The `Socket` library doesn't buffer? Then why does the documentation for `Socket` mention "bytes buffered on the socket" in several spots, in particular in the documentation for `getInputStream` (which Julen is using)?
R. Bemrose
Because the *kernel* has socket send and receive buffers. And you still haven't answered my 2nd question.
EJP
A: 

Note that big chunks of data can be divided into several packages when sending over sockets. I wrote an answer here regarding sockets in C++, that addresses it shortly.

I see three possibilities:

  • Your tcp stack could be full. Thats a real bugger. You can read more about that in this article, but in short: the socket is full in some end of your socket, making the sender block more writes. You will have to read that data from the receiving side before send will unblock. You can check for "TCP ZeroWindow" with wireshark to find this. (default settings will be black with red text, you can't miss it)
  • It could be your sending side that is waiting for you to push more data to send
  • I don't think this is valid, but I guess that the receiving side could as well wait for more data to receive. As I understand it it is really up to the underlying network to decide if the data should be sent or not.

You can use select (sorry, don't know of the unix equivalent arguments, or java's) when sending data to check if you are ok to actually send (also described in my answer here).

Default
`select` is part of C, so I'm assuming it's in C++ as well.
R. Bemrose
@R. Bemrose, is it the same arguments? Microsoft likes to change everything :) Because that link goes to msdn - winsock library.
Default
Actually, select is not part of C, it's part of POSIX, coming from BSD. It was added to BSD together with sockets in 4.2, it appears on Winsock because of that.
ninjalj
As for compatibility between POSIX and Winsock select(), the only important difference I can see is that Winsock apparently sets errorfd s on failure to connect on a non-blocking socket, while it should set writefds
ninjalj
'socket is full in some end of your socket, making both ends block'. This is not correct. A socket send buffer being full doesn't make both ends block. It makes the sending end block. The other end can read, and it can write until it fills up its own socket send buffer.
EJP
@EJP: hm.. I just took it from my personal experience that both ends blocked. Although, I wrote alot from both ends so it might just be that both my ends filled their respective buffers themselves, thus both blocking. I'll add your comment, thanks
Default
+1  A: 

THe BufferedReader is not the problem specifically, and neither is 'the TCP stack [being] full'. And select() isn't required to solve it.

You are making several common mistakes here.

  1. You are ignoring the return value of read(). It could be -1, indicating that the peer has closed the connection, which you must test for and act on first. Or it could be any value between 1 and the size you requested. You are just blindly assuming you will get 5 bytes when you call in.read(buffer,0,5). There's no guarantee of that. You need to use DataInputStream.readFully().

  2. You are sending 8-bit chars from C++, and using a Reader in Java. This doesn't make any sense whatsoever. Use an InputStream. Specifically, a DataInputStream so you can call readFully() as suggested above.

  3. Socket.isClosed() tells you whether you have closed the socket. It doesn't tell you whether the peer has closed the connection. That's what the -1 above is for.

  4. Similarly Socket.isInputShutdown() tells you whether you have shutdown input on this socket. It doesn't tell you whether the peer has shutdown output at his end. Again, that's what the -1 above is for.

So both those tests are pointless, and the message you are printing when either of them is true is incorrect.

EJP