【问题标题】:Java, Getting a weird Socket Exception: "Broken pipe" and "Operation timed out"Java,得到一个奇怪的套接字异常:“Broken pipe”和“Operation timed out”
【发布时间】:2011-11-11 04:16:04
【问题描述】:

我有一个客户端服务器应用程序,它有 16 个线程(8 个客户端,8 个服务器),每个线程都有一个 1-1 匹配的 TCP 连接(所以 8 个 TCP 流)。

我让服务器发送 X 数量的随机字节然后关闭。同时客户端只是读取 X 量的数据然后关闭。 X 是预先确定的。我也在使用 dummynet 进行带宽限制,但我正在为管道提供足够的带宽(100Mbps)。有时它工作正常,有时我得到这些例外。我在大约 3.5 分钟内将 1GB 均匀分布在所有 8 个连接上。

客户端抛出此异常:

java.net.SocketException: Operation timed out
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:129)
at miccbull.parralleltcp.client.StreamWorker.run(StreamWorker.java:43)

服务器抛出此异常:

java.net.SocketException: Broken pipe
at java.net.SocketOutputStream.socketWrite0(Native Method)
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:92)
at java.net.SocketOutputStream.write(SocketOutputStream.java:124)
at miccbull.parralleltcp.server.TransmissionWorker.run(TransmissionWorker.java:51)

服务器代码:

public void run() {

    OutputStream os = null;

    try {
        socket = sSocket.accept();
        os = socket.getOutputStream();
    } catch (IOException e2) {
        e2.printStackTrace();
    }

    //send the data
    for(int i = 0; i < Server.TRANSMISSIONS; i++){
        System.out.println(sSocket.getLocalPort() + " sending set " + (i+1) + " of " + Server.TRANSMISSIONS);

        try {
            os.write(new byte[Server.FILE_SIZE/Server.numStreams/Server.TRANSMISSIONS]);
            os.flush();
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("Closing server (at write bytes) with socket id: " + sSocket.getLocalPort());
        } 
    }

    System.out.println("Worker " + sSocket.getLocalPort() + " done");

    //close the socket
    try {
        socket.close();
        sSocket.close();
    } catch (IOException e) {
        e.printStackTrace();
    }

}

客户代码:

    public void run(){

    byte[] bytes = new byte[1024];  //number of bytes to read per client stream
    InputStream is = null;

    //connect to server
    try {
        connectionSocket = new Socket("localhost", id);
        is = connectionSocket.getInputStream();
    } catch (UnknownHostException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }


    //read file from server
    int value = 0;
    int bytesRead = 0;
    try {

        while(bytesRead < (Client.FILE_SIZE/Client.NUM_STREAMS)){
            value = is.read(bytes, 0, 1024);
            if(value == -1){
                System.out.println("******************************** Read is -1 for client " + id);
            }
            else if(value == 0){
                System.out.println("******************************** Read is 0 for client " + id);
            }
            bytesRead += value;
        }
    } catch (IOException e) {
        System.out.println("**** Exception in read in client " + id + " and value value was: " + value);
        if(bytesRead == (Client.FILE_SIZE/Client.NUM_STREAMS)){
            System.out.println("************ NOT ACTUALLY BAD" + id);
        }
        e.printStackTrace();
    }

    //Finished download
    Client.workerDone();
    System.out.println("Worker " + id + " done received " + bytesRead);

导致这些异常的原因是什么?

【问题讨论】:

    标签: java sockets exception tcp


    【解决方案1】:

    您的客户永远不会停止阅读,因为您没有测试 read() 返回

    【讨论】:

    • 嗨,当我从服务器收到我期望的所有字节时,我停止阅读,特别是在这种情况下bytesRead &lt; (Client.FILE_SIZE/Client.NUM_STREAMS)。尽管如此,我还是对从 read() 返回的值进行了一些检查,在我的实验过程中它永远不会
    • 这令人非常沮丧。感谢您的帮助。
    • @Michael 不过你的代码是错误的。如果服务器在发送您期望的所有数据之前断开连接怎么办?您的代码不会检测到这一点,并将永远循环。
    【解决方案2】:

    这是我在您的代码中看到的:

    1. 我已经验证了对socket.getOutputStream()socket.getInputStream() 的每次调用都会返回一个与套接字关联的不同 流。您应该为每个套接字调用一次,并将结果放入一个局部变量中。

      OutputStream outputStream = socket.getOutputStream();
      // send the data
      for (int i = 0; i < 10; i++) {
          ....
          outputStream.write(...);
      
    2. 您应该从 run() 方法返回许多地方,但我怀疑您知道这一点。

    3. 您没有检查来自 read() 的返回值以查看它是否在 EOF 上返回 -1。你不应该只是假设你得到了正确的字节数。

    4. 我假设您正在编写空字符块是有原因的。

    【讨论】:

    • 1. “我已经验证了对 socket.getOutputStream() 和 socket.getInputStream() 的每次调用都会返回与套接字关联的不同流。”我刚刚验证了与源代码相反的情况。所以最终这根本不是他的问题。 1.1。刷新这样的流没有任何作用。
    • @Gray 嗨,我认为流是相同的,但我按照您的建议将它们放入局部变量中,并且我已经检查了 read() 中的值。我刚刚运行测试并在客户端收到了 BrokenPipe 异常,最近读取值为 162。我正在发送随机字节,因为此应用程序仅用于性能测试。您还能看到其他可疑之处吗?
    • @EJP,嗯,我无法访问我的 Mac 上的 JDK 源代码(抱怨),但对象具有不同的 toString() 值,即 Object.hashCode(),所以它们是不同的对象,除非我我错过了一些东西。我正在运行 Sun JDK 1.6.0_26。感谢read 的更正。
    • @Michael,您期望 read 的哪些值?由于缓冲和数据包数据斩波,您不会每次都获得完整的 1024 读取。 read 不会阻塞,直到它具有整个缓冲区的价值。如果您尝试发送“实体”,那么我建议您使用序列化以及写入和读取对象。否则,您将不得不使用BufferedInputStream 等进行自己的缓冲区维护。
    • @Gray 我可以接受来自read() 的任何正值,因为我只是将该值添加到已读取的总量(value)中(bytesRead)。然后当bytesRead 成为我期望从服务器获得的值时,run 结束。我刚刚确认客户端在从服务器读取所有数据之前确实抛出了这个“操作超时”异常。感谢您迄今为止的帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-06
    • 1970-01-01
    • 2013-12-10
    • 2013-05-01
    • 1970-01-01
    • 2016-03-30
    相关资源
    最近更新 更多