首页 > 代码库 > java socket报文通信(二)报文的封装
java socket报文通信(二)报文的封装
昨天我们谈了怎么建立socket通信的服务端和客户端,今天我们就来谈一谈怎么封装报文。
什么是报文这里我就不在阐述了,不清楚的朋友可以自己去查资料。我们今天要谈的报文主要友以下几个部分组成:
3位同步校验位+8位报文长度+报文头+报文体+32位MD5校验位
基本格式如下:
0X110X120X1300000232<?xml version="1.0" encoding="GBK"?><ROOT><Code>0204</Code><Date>20141223</Date><No>141223010008152</No><Code>17010001</Code><Name>张三</Name></ROOT>B251AB76B11114DB176023A0AA27A524
说明:
前面的0X110X120X13是3位16进制的同部位,这里为了大家理解,所以就以字符的形式谢出来了。00000232是报文长度。<?xml version="1.0" encoding="GBK"?><ROOT><Code>0204</Code><Date>20141223</Date><No>141223010008152</No><Code>17010001</Code></ROOT>是报文头。即每个报文都包含的信息。<Name>张三</Name>是报文体。B251AB76B11114DB176023A0AA27A524是加密数据。
关于如何将对象转换为xml格式的报文我将在下一篇写,这里主要是给大家如何将如上的这些字符串转化为字节以及如何发送和接收报文。
1.建立报文的对象
public class SocketPacket { private String bodyLen; private String body; private String syncStr; private String md5; public String getBodyLen() { return bodyLen; } public String getBody() { return body; } public String getSyncStr() { return syncStr; } public String getMd5() { return md5; } public void setBodyLen(String bodyLen) { this.bodyLen = bodyLen; } public void setBody(String body) { this.body = body; } public void setSyncStr(String syncStr) { this.syncStr = syncStr; } public void setMd5(String md5) { this.md5 = md5; } public byte[] getByteStream() throws UnsupportedEncodingException{ byte[] bodyBytes = this.body.getBytes("gbk");//获得body的字节数组 int bodyLength = bodyBytes.length; int socketLength = 3+bodyLength+8+32; byte [] soc = new byte[socketLength]; //添加校验数据 int index = 0; soc[0]=0x11; soc[1]=0x12; soc[2]=0x13; index+=3; //添加8位报文长度(我的博文中也有NumberFormat的用法介绍) NumberFormat numberFormat = NumberFormat.getNumberInstance(); numberFormat.setMinimumIntegerDigits(8); numberFormat.setGroupingUsed(false); byte [] num = numberFormat.format(socketLength).getBytes(); for(int i = 0;i<8;i++){ soc[index++]= num[i]; } //添加body内容 for(int i = 0;i<bodyLength;i++){ soc[index++] = bodyBytes[i]; } //添加md5校验码 byte [] md5Bytes = this.md5.getBytes(); for (int i = 0; i < num.length; i++) { soc[index++] = md5Bytes[i]; } return soc; } //字节装转报文string public String getString(byte [] socketBytes){ String syncStr = this.bytesToString(socketBytes, 0, 3); String socketLength = this.bytesToString(socketBytes, 3, 3+8); String body = this.bytesToString(socketBytes, 3+8, socketBytes.length-32); String md5 = this.bytesToString(socketBytes,socketBytes.length-32,socketBytes.length); return syncStr+socketLength+body+md5; } //将字节数组转化为string public String bytesToString(byte [] bytes,int start,int end){ String str = ""; if(bytes.length<end-start){ return str; } byte [] bs = new byte[end-start]; for(int i = 0;i<end-start;i++){ bs[i] = bytes[start++]; } str = new String(bs); return str; } public String toString(){ return this.syncStr+this.bodyLen+this.body+this.md5; } }
2.封装发送和接收报文的工具类
/** * 报文发送 */public class SockeUtil { Socket socket = null; public SockeUtil(String ip,int port) throws UnknownHostException, IOException{ socket = new Socket(ip, port); } // public SocketPacket sentSocket(SocketPacket socketPacket) throws UnsupportedEncodingException, IOException{ SocketPacket sPacket = new SocketPacket(); OutputStream output=null; InputStream input =null; // 同步字符串(3byte) byte[] sync = null; // byte[] bodyLen = null; // 8位长度 byte[] body = null; // 内容 byte[] md5 = null; // MD5 output = socket.getOutputStream(); //写数据发送报文 output.write(socketPacket.getByteStream()); //获得服务端返回的数据 input = socket.getInputStream(); sync = this.streamToBytes(input,3); bodyLen = this.streamToBytes(input, 8); String lenString = new String(bodyLen); int len = Integer.valueOf(lenString); body = this.streamToBytes(input, len); md5 = this.streamToBytes(input, 32); sPacket.setSyncStr(new String(sync,Charset.forName("gbk"))); socketPacket.setBodyLen(new String(bodyLen,Charset.forName("gbk"))); socketPacket.setBody(new String(body,Charset.forName("gbk"))); socketPacket.setMd5(new String(md5,Charset.forName("gbk"))); return sPacket; } public byte[] streamToBytes(InputStream inputStream,int len){ /** * inputStream.read(要复制到得字节数组,起始位置下标,要复制的长度) * 该方法读取后input的下标会自动的后移,下次读取的时候还是从上次读取后移动到的下标开始读取 * 所以每次读取后就不需要在制定起始的下标了 */ byte [] bytes= new byte[len]; try { inputStream.read(bytes, 0, len); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return bytes; }}
3.在封装一个调用报文发送的类:
public String socket(SocketPackage socketPackage) throws UnsupportedEncodingException{ SocketClient socketClient=null;; try { socketClient = new SocketClient(ip,端口); } catch (UnknownHostException e) { log.error("socket链接异常,链接信息:"+ip+端口); e.printStackTrace(); } catch (IOException e) { log.error("socket IO异常"); e.printStackTrace(); } SocketPackage s = null; try { s = socketClient.sendMsg(socketPackage); } catch (Exception e) { try { log.error("socket发送消息异常,发送信息:"+new String(socketPackage.getByteStream(),"GBK")); } catch (UnsupportedEncodingException e1) { log.error("socket将socketPackage转为字符串异常,socketPackage信息:"+socketPackage.getByteStream()); e1.printStackTrace(); } e.printStackTrace(); } String result = ""; try { result = new String(s.getStream(),"GBK"); } catch (UnsupportedEncodingException e) { log.error("socket将socketPackage转为字符串异常,socketPackage信息:"+socketPackage.getByteStream()); e.printStackTrace(); } return result ; }
这样我们就能发送报文和接收报文了!赶紧试一下吧!^_^
java socket报文通信(二)报文的封装