响应报文格式如下
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的时候,表示报文已经读取完整了,可以关闭连接了。
public static void main(String[] args) {
String host = "localhost";
int port = 8899;
String msg = "hello";
try (Socket socket = new Socket(host, port);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()
) {
// 向服务端socket推送报文
OutputStream out = socket.getOutputStream();
out.write(msg.getBytes(StandardCharsets.UTF_8));
out.flush();
InputStream in = socket.getInputStream();
byte[] buf = new byte[1024];
// 接收服务端socket返回的6位报文长度
int len;
byte[] lenBytes = new byte[6];
BufferedInputStream bufferIn = new BufferedInputStream(in);
bufferIn.read(lenBytes);
int dataLen = Integer.parseInt(new String(lenBytes));
// 根据6位报文长度读取报文内容
while ((len = bufferIn.read(buf)) != -1) {
byteArrayOutputStream.write(buf, 0, len);
// 包长减去实际读取的字节数,可能是1024,也可能不是
dataLen = dataLen - len;
// 剩余需要读取的字节数小于或者等于0的时候,表示报文已经读取完整
if (dataLen <= 0)
break;
}
String result = byteArrayOutputStream.toString("UTF-8");
System.out.println(result);
socket.shutdownInput();
socket.shutdownOutput();
} catch (Exception e) {
e.printStackTrace();
}
}
方法三:
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
public class SocketClient {
public static void main(String[] args) {
String host = "localhost";
int port = 8899;
String msg = "hello";
try (Socket socket = new Socket(host, port);
InputStream in = socket.getInputStream();
BufferedInputStream bufferIn = new BufferedInputStream(in)
) {
// ------------------------------向服务端socket推送报文
OutputStream out = socket.getOutputStream();
out.write(msg.getBytes(StandardCharsets.UTF_8));
out.flush();
socket.shutdownOutput();
// ------------------------------接收socket服务端响应定长报文
// 接收服务端socket返回的6位报文长度
byte[] lenBytes = new byte[6];
bufferIn.read(lenBytes);
// 6位报文长度
int dataLen = Integer.parseInt(new String(lenBytes));
int offset = 0;
// 已读取报文长度
int readLen;
byte[] res = new byte[dataLen];
// 根据6位报文长度读取报文内容
while (offset < dataLen) {
readLen = in.read(res, offset, Math.min(1024, dataLen - offset));
offset += readLen;
}
String result = new String(res, StandardCharsets.UTF_8);
System.out.println("接收socket服务端响应定长报文:" + result);
} catch (Exception e) {
e.printStackTrace();
}
}