在和銀聯進行聯機交易時,突然出現無法讀取響應的情況;
報錯信息如下:
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);
至此,解決了這個問題;
