与第三方业务系统对接,采用socket协议传输报文。
响应报文格式如下
000530<?xml version="1.0" encoding="utf-8"?><root>
<dstype>resp</dstype>
<dscode>DS01</dscode>
<seqnum>144819675072211</seqnum>
<dstime>20151122 20:52</dstime>
<rescode>1</rescode>
<resdesc>成功</resdesc>
<dwbh>003870</dwbh>
<dwmc>xxxxx人民政府接待科</dwmc>
<dwxz></dwxz>
<xzqh>110102</xzqh>
<dwdz>镇府前路行政大楼一楼104</dwdz>
<dwfzr>xx</dwfzr>
<lxdh> dsd</lxdh>
<dwgjjzh>0</dwgjjzh>
<hjqsny>201511</hjqsny>
<khrq>34</khrq>
<jbjgbh>建行xx支行</jbjgbh>
<zck>90</zck>
<jcrs>652</jcrs>
<jczt>缴存</jczt>
</root>
报文前6位是包长度,刚开始使用下面这种方式读取数据:先读取前6位,得到包长度,每次读取1024个字节,按1024个字节计算出需要读取的次数,剩余的再一次性读取。
例如包长为2049,则读取两次1024个字节,然后剩余的1个字节再一次性读取出来。
以上逻辑在实际操作的时候碰到一个问题,在执行read方法读取1024个字节的时候,并非每次都能正常读取到1024个字节,最终导致报文不完整。
int packSize = 1024;
Socket socket = null;
PrintWriter printWriter = null;
DataInputStream dis = null;
ByteArrayOutputStream out = null;
try
{
socket = new Socket(config.getIp(), config.getPort());
//通过printWriter 来向服务器发送消息
printWriter = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"));
//发送消息
printWriter.println(xml);
printWriter.flush();
//接收信息 获取包的长度
dis = new DataInputStream(socket.getInputStream());
byte[] lenBytes = new byte[6];
dis.read(lenBytes);
String lenStr = new String(lenBytes, "UTF-8");
Integer len = Integer.valueOf(lenStr);
//包的数量
int packetCount = len / packSize;
//最后一个包的大小
int lastDataPacket = len - (packSize * packetCount);
byte[] data = new byte[packSize];
out = new ByteArrayOutputStream();
for (int i = 0; i < packetCount; i++)
{
int j = dis.read(data);
out.write(data, 0, j);
}
if (lastDataPacket > 0)
{
data = new byte[lastDataPacket];
int j = dis.read(data);
out.write(data, 0, j);
}
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
//关闭连接
try
{
if (out != null) out.close();
if (printWriter != null) printWriter.close();
if (dis != null) dis.close();
if (socket != null) socket.close();
}
catch (Exception ignored)
{
}
}
if (out != null)
{
return new String(out.toByteArray(), "UTF-8");
}
后来调整了一下思路,具体实现如下,依然先获取到包长,是为了读取完了之后关闭连接。
依然每次读取1024个字节,在while循环里每次记录剩余需要读取的字节数(将包长减去实际读取的字节数,可能是1024,也可能不是)。
当剩余需要读取的字节数小于或者等于0的时候,表示报文已经读取完整了,可以关闭连接了。
Socket socket = null;
try
{
socket = new Socket(config.getIp(), config.getPort());
socket.setSendBufferSize(IOUtils.cacheSize);
socket.setReceiveBufferSize(IOUtils.cacheSize);
OutputStream out = socket.getOutputStream();
out.write(xml.getBytes("UTF-8"));
out.flush();
InputStream in = socket.getInputStream();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
BufferedInputStream bufferIn = new BufferedInputStream(in);
byte[] buf = new byte[1024];
int len;
byte[] lenBytes = new byte[6];
bufferIn.read(lenBytes);
Integer dataLen = Integer.valueOf(new String(lenBytes));
while ((len = bufferIn.read(buf)) != -1)
{
byteArrayOutputStream.write(buf, 0, len);
dataLen = dataLen - len;
if (dataLen <= 0)
break;
}
return new String(byteArrayOutputStream.toByteArray(), "UTF-8");
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
//关闭连接
IOUtils.close(socket);
}