在和银联进行联机交易时,突然出现无法读取响应的情况;
报错信息如下:
java.net.SocketException: Connection reset at java.net.SocketInputStream.read(SocketInputStream.java:196) at java.net.SocketInputStream.read(SocketInputStream.java:122) at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:283) at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:325) at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:177) at java.io.InputStreamReader.read(InputStreamReader.java:184) at java.io.BufferedReader.fill(BufferedReader.java:154) at java.io.BufferedReader.readLine(BufferedReader.java:317) at java.io.BufferedReader.readLine(BufferedReader.java:382)
Connection reset是服务器关闭了连接,一直认为是服务器错误导致的;
后来发现是代码中使用了 socket的readline方法导致的;
原代码如下:
socket = new Socket(this.serverHost, this.serverPort); socket.setSoTimeout(timeOut); writer = new PrintWriter(socket.getOutputStream()); log.info("准备发送服务端数据: " + msg); writer.println(msg); writer.flush(); log.info("请求完成, 准备接收返回"); reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), Encoding.GBK)); String resp = reader.readline();
......
readline()方法会读到流结束或者\n的时候返回。
读取文件时,文件结尾就代表流结束,但是socket没有关闭的话就不会结束这个流。服务器在消息的结尾如果没有发送换行符 \n 的话,也不会读取结束;
解决方案:每次读取的报文大小由报文头决定
socket = new Socket(this.serverHost, this.serverPort); socket.setSoTimeout(timeOut); writer = new PrintWriter(socket.getOutputStream()); log.info("准备发送服务端数据: " + msg); writer.println(msg); writer.flush(); log.info("请求完成, 准备接收返回"); reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), Encoding.GBK)); char[] rDataLen = new char[4]; reader.read(rDataLen, 0, 4); int lenth = Integer.parseInt(new String(rDataLen)); char[] rContentTxt = new char[lenth]; reader.read(rContentTxt, 0, lenth); String response = new String(rDataLen) + new String(rContentTxt);
至此,解决了这个问题;