当前位置:   article > 正文

read方法阻塞的解决

read方法阻塞的解决

转载自别人的博客

  1. 在网络编程中,读取数据时遇到了该问题:服务器端运行到read方法停住了,不再往后运行。
    代码如下:
客户端:
public class SocketClient {
     
    public static void main(String[] args) throws UnknownHostException, IOException, InterruptedException {
        Socket client = new Socket("localhost",8888);
        OutputStream out = client.getOutputStream();
        InputStream input = client.getInputStream();
 
        out.write("sender say hello socket".getBytes());
        out.flush();
         
        read(input);
        out.close();
    }
    public static void read(InputStream input) throws IOException {
         byte[] buf = new byte[128];
         int size = 0;
         while ((size = input.read(buf,0,buf.length)) != -1) {
             System.out.print(new String(buf));
         }
    }
}
 
 
服务端:
public class SocketServer {
    public static void main(String[] args) {
        SocketServer ss = new SocketServer();
        int port = 8888;
        try {
            ss.startServer(port);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public void startServer(int port) throws Exception {
        ServerSocket serverSocket = new ServerSocket(port);
        Socket server = null;
        try {
            while (true) {
                server = serverSocket.accept();
                System.out.println("server socket is start……");
                try {
                    BufferedReader input = new BufferedReader(new InputStreamReader(new ByteArrayInputStream("服务端发给客户端的信息".getBytes())));
                    BufferedInputStream in = new BufferedInputStream(server.getInputStream());
                    PrintWriter out = newPrintWriter(newOutputStreamWriter(server.getOutputStream()));
                     
                    String clientstring = null;
                    out.println("欢迎客户端连入");
                    out.flush();
                    byte[] buf = new byte[128];
                    int size = 0;
                    while (( size = in.read(buf,0,buf.length)) != -1) {
                        System.out.println(new String(buf));
                    }
                    out.print(" client is over");
                    out.flush();
                    out.close();
                    System.out.println(" client is over");
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    server.close();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            serverSocket.close();
        }
    }
     
    
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74

这段代码执行以后会发现server类 read()方法发生了阻塞,经过查找资料发现 read() 是一个阻塞函数,如果客户端没有声明断开outputStream那么它就会认为客户端仍旧可能发送数据,像read()这种阻塞读取函数还有BufferedReader类种的 readLine()、DataInputStream种的readUTF()等。
2. 解决方案
1)Socket任意一端在调用完write()方法时调用shutdownOutput()方法关闭输出流,这样对端的inputStream上的read操作就会返回-1, 这里我们要注意下不能调用socket.getInputStream().close()。因为它会导致socket直接被关闭。 当然如果不需要继续在socket上进行读操作,也可以直接关闭socket。但是这个方法不能用于通信双方需要多次交互的情况。

out.write("sender say hello socket".getBytes());
out.flush();
client.shutdownOutput();  //调用shutdown 通知对端请求完毕
  • 1
  • 2
  • 3

这个解决方案缺点非常明显,socket任意一端都依赖于对方调用shutdownOutput()来完成read返回 -1,如果任意一方没有执行shutdown函数那么就会出现问题。所以一般我们都会在socket请求时设置连接的超时时间 socket.setSoTimeout(5000);以防止长时间没有响应造成系统瘫痪。

while (true) {
     server = serverSocket.accept();
     System.out.println("server socket is start……");
     server.setSoTimeout(5000);
     .....
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

2)发送数据时,约定数据的首部固定字节数为数据长度。这样读取到这个长度的数据后,就不继续调用read方法
这种方式优点是不依赖对方调用shutdown函数,响应较快,缺点是数据传输是最大字节数固定,需双方事先约定好长度,伸缩性差。
3)发送数据时,约定前几位返回数据byte[]长度大小或最后输出 \n 或 \r 作为数据传输终止符。

客户端
 
        out.write("sender say hello socket \n".getBytes());
    out.flush();
 
服务器端
 
        byte[] buf = new byte[1];
        int size = 0;
        StringBuffer sb = new StringBuffer();
        while (( size = in.read(buf,0,buf.length)) != -1) {
            String str = new String(buf);
            if(str.equals("\n")) {
                break;
            }
            sb.append(str);
            System.out.print(str);
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

这种方式是对第二种方案的改良版,但不得不说 这是目前socket数据传输的最常用处理read()阻塞的解决方案。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/280246
推荐阅读
相关标签
  

闽ICP备14008679号