昨天我們談了怎么建立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 ; }這樣我們就能發送報文和接收報文了!趕緊試一下吧!^_^
新聞熱點
疑難解答