在做socket请求对方接口的时候遇到了以下问题
1、第一次使用固定的字节长度4096来读取对方返回的数据时遇到了没读完的情况,这时候怀疑设置的长度问题
sClient = new Socket(ip, 端口);
sClient.setSoTimeout(超时时间);
byte[] sendBytes = BasicUtil.str2bcd(reqXml);
sClient.getOutputStream().write(sendBytes, 0, sendBytes.length);
sClient.getOutputStream().flush();
byte[] dataLen = new byte[4096];
sClient.getInputStream().read(dataLen);
String result = new String(dataLen); //读取的数据不完整
2、这时候换成了下面使用循环来读的方法,这时候又出现了另外的问题,发现数据循环已经读完了还一直没结束,直到一分钟才返回,这时候想到自己设置的超时时间是1分钟,觉得有它的原因,但是超时时间是如果读完立马返回是没有影响的啊。后面才想到对方使用的是长连接的方式,因为对方一直不关闭我这边就认为没读完,就会一直读完还会继续等待,直到超时时间结束。
sClient = new Socket(ip, 端口);
sClient.setSoTimeout(超时时间);
byte[] sendBytes = BasicUtil.str2bcd(reqXml);
OutputStream os = sClient.getOutputStream();
os.write(sendBytes, 0, sendBytes.length);
os.flush();
InputStream inputStream = sClient.getInputStream();
byte[] dataLen = new byte[1024];
int len2;
while((len2 = inputStream.read(dataLen)) != -1) {
result.append(new String(dataLen,0,len2, StandardCharsets.UTF_8));
logger.info("原始返回报文" + result);
}
3、第三次优化,因为这时候还没对方的文档,不知道是采用什么协议,所以这次就每次读64字节,然后设置超时时间为1秒,这次能读完了,但是后台却会报读取超时的异常,虽然没什么影响,想到这,原因还是因为长连接的问题,因为最后一次发起请求到超时时间结束还没拿到结果。
sClient = new Socket(ip, 端口);
sClient.setSoTimeout(1秒);
byte[] sendBytes = BasicUtil.str2bcd(reqXml);
OutputStream os = sClient.getOutputStream();
os.write(sendBytes, 0, sendBytes.length);
os.flush();
InputStream inputStream = sClient.getInputStream();
byte[] dataLen = new byte[64];
int len2;
while((len2 = inputStream.read(dataLen)) != -1) {
result.append(new String(dataLen,0,len2, StandardCharsets.UTF_8));
logger.info("原始返回报文" + result);
}
4、拿到文档后才知道对方返回的报文中前2个字节代表的是此次报文的总长度
5、这时候就知道了,要先读取获取到整个报文的长度字节,最后再尝试多次后
sClient = new Socket(serverIp, Integer.parseInt(port));
sClient.setSoTimeout(Integer.parseInt(timeOut));
byte[] sendBytes = BasicUtil.str2bcd(reqXml);
sClient.getOutputStream().write(sendBytes, 0, sendBytes.length);
sClient.getOutputStream().flush();
byte[] dataLen = new byte[2];
sClient.getInputStream().read(dataLen);
short buffer = ByteBuffer.wrap(dataLen).order(ByteOrder.BIG_ENDIAN).getShort();;
logger.info("----------->length: " + buffer);
dataLen=new byte[buffer];
sClient.getInputStream().read(dataLen);
String result = new String(dataLen,"GBK"); //new String(arr);
先读取2字节,前2个字节代表报文长度,拿到长度再度一次剩下的字节