在Ubuntu或Windows中运行的Java程序中套接字的不同行为

时间:2010-06-24 07:34:22

标签: java c++ windows sockets ubuntu

我正在使用标准套接字连接两个程序之间的通信,一个是C ++,另一个是Java。这两个程序在同一台机器上的UNIX(Ubuntu)下运行,并定期共享一段时间的信息。在执行的某个时刻,并且总是在同一点上它被卡住,因为C ++中的程序发送信息而Java中的程序没有获得所有信息,所以它们阻塞,因为第一个期望接收它而第二个不发送因为没有收到第一个地方的信息。

奇怪的是你在Windows下用Java执行程序。然后它工作正常,程序正确结束,没有任何集团。

我认为Java应用程序存在问题,但为什么运行Ubuntu或Windows下的区别呢?套接字的行为有何不同?某些参数是否与Ubuntu和Windows中的JVM不同?

非常感谢你!

Julen。

编辑:

这是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 个答案:

答案 0 :(得分:2)

BufferedReader不是具体问题,也不是'TCP堆栈[正在]满“。并且select()不需要解决它。

你在这里犯了几个常见的错误。

  1. 您忽略了read().的返回值它可能为-1,表示对等方已关闭连接,您必须先测试该连接并采取行动。或者它可以是介于1和您请求的大小之间的任何值。你只是盲目地假设你在拨打in.read(buffer,0,5).时会得到5个字节。不能保证这一点。您需要使用DataInputStream.readFully().

  2. 您正在从C ++发送8位字符,并在Java中使用Reader。这没有任何意义。使用InputStream.具体而言,如上所述DataInputStream so you can call readFully()

  3. Socket.isClosed()告诉您是否关闭了套接字。它不会告诉您对等方是否已关闭连接。这就是上面-1的含义。

  4. 同样Socket.isInputShutdown()告诉您是否在此套接字上有关闭输入。它不会告诉您对等端是否在其结束时具有关闭输出。再次,这就是上面的-1。

  5. 因此,这些测试都毫无意义,当其中任何一个为真时打印的消息都是错误的。

答案 1 :(得分:1)

使用嗅探器检查通信。 Wireshark是一个很好的。

答案 2 :(得分:1)

虽然BufferedReader非常适合文件操作,但在从Socket读取时使用它是一个非常糟糕的主意。

否则,BufferedReader可能认为数据仍未进入缓冲区,而实际上并非如此。

我建议将其删除并直接处理InputStreamReader以查看问题是否仍然存在。

答案 3 :(得分:0)

请注意,通过套接字发送时,大块数据可以分成几个包。我写了一篇关于C ++中套接字的答案here,很快就解决了这个问题。

我看到三种可能性:

  • 您的tcp堆栈可能已满。这是一个真正的错误。您可以阅读有关in this article的更多信息,但简而言之:套接字的某些端插槽已满,使发送方阻止更多写操作。在send取消阻止之前,您必须从接收方读取该数据。您可以使用wireshark检查“TCP ZeroWindow”以查找此信息。 (默认设置为黑色,红色文字,你不能错过)
  • 可能是您的发送方等待推送更多数据发送
  • 我不认为这是有效的,但我想接收方也可以等待接收更多数据。据我所知,确定是否应该发送数据取决于底层网络。

您可以在发送数据时使用select(抱歉,不知道unix等效参数或java),以检查您是否可以实际发送(在我的回答here中也有描述) )。