昨天我们谈了怎么建立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报文通信(二)报文的封装的更多相关文章

  1. Java Socket实战之二:多线程通信

    转自:http://developer.51cto.com/art/201202/317544.htm 上一篇文章说到怎样写一个最简单的Java Socket通信,但是在上一篇文章中的例子有一个问题就 ...

  2. java socket通讯(二)处理多个客户端连接

    通过java socket通讯(一) 入门示例,就可以实现服务端和客户端的socket通讯,但是上一个例子只能实现一个服务端和一个客户端之间的通讯,如果有多个客户端连接服务端,则需要通过多线程技术来实 ...

  3. java socket线程通信

    关于socket线程通信的一些知识整理 一般我们需要要让两台机子进行通信,需要创建一个Server 类,一个Client类,还需要创建一个线程类 server public class Server ...

  4. JAVA Socket编程(二)之TCP通信

    基于TCP(面向连接)的socket编程,分为客户端和服务器端. 客户端的流程如下: (1)创建套接字(socket) (2)向服务器发出连接请求(connect) (3)和服务器端进行通信(send ...

  5. Java Socket编程----通信是这样炼成的

    Java最初是作为网络编程语言出现的,其对网络提供了高度的支持,使得客户端和服务器的沟通变成了现实,而在网络编程中,使用最多的就是Socket.像大家熟悉的QQ.MSN都使用了Socket相关的技术. ...

  6. java基础知识回顾之java Socket学习(二)--TCP协议编程

    TCP传输(传输控制协议):TCP协议是一种面向连接的,可靠的字节流服务.当客户端和服务器端彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能进行数据的传输.它将一台主机发出的字节流无差错的 ...

  7. Java Socket应用---通信是这样练成的

    网络基础简介 Java 中网络相关 API 的应用     Java 中的 InetAddress 的应用   Test01.java package com.imooc; import java.n ...

  8. JAVA知识总结(二):封装

    时隔近一年,我突然想起来这个文章还没有发完,所以就继续开始写.也不知道自己上次写到哪里了,不管了这里从面向对象的三个特性说起. 类和对象 在这之前,我们先了解什么是对象,已经什么是面向对象?对象:万物 ...

  9. Java Socket编程基础篇

    原文地址:Java Socket编程----通信是这样炼成的 Java最初是作为网络编程语言出现的,其对网络提供了高度的支持,使得客户端和服务器的沟通变成了现实,而在网络编程中,使用最多的就是Sock ...

随机推荐

  1. Multipatch对象

    Multipatch对象是 TriangleStrip 和TriangleFan, Trangle,Ring对象的集合 TriangleStrip TriangleFan Trangle

  2. Querylayer(查询图层) - 浅谈

    Querylayer(查询图层)是通过 SQL 查询定义的图层或独立表.通过 Querylayer 可将空间信息和非空间信息都存储在DBMS 中,从而使这些信息可以轻松地整合到 ArcMap 中的各 ...

  3. oracle获得每周,每月,每季度,每年的第一天

    当前年月日 SELECT trunc(sysdate) , trunc(sysdate,'dd') FROM dual   当年第一天 SELECT trunc(sysdate,'yyyy') FRO ...

  4. Oracle 大数据处理(一)

    数据量:  日数据 2000万   月数据 8000万 处理方式:建立父子分区,采用Range+list模式分区,日期作为主分区,地域作为子分区 索引选择: 由于应用于查询比较多,故建立位图索引,效率 ...

  5. Tiling_easy version(填2 x N的格子的种类)

    E - Tiling_easy version 题目大意: 有一个大小是 2 x n 的网格,现在需要用2种规格的骨牌铺满,骨牌规格分别是 2 x 1 和 2 x 2,请计算一共有多少种铺设的方法. ...

  6. jQuery模拟点击A标记

    这个问题弄了半小时没想明白,后来觉得是这样的. 菜单 <li class="menu"><a href="xxx.com" target=&q ...

  7. 10 条建议让你创建更好的 jQuery 插件

    在开发过很多 jQuery 插件以后,我慢慢的摸索出了一套开发jQuery插件比较标准的结构和模式.这样我就可以 copy & paste 大部分的代码结构,只要专注最主要的逻辑代码就行了. ...

  8. memcached学习笔记——存储命令源码分析下篇

    上一篇回顾:<memcached学习笔记——存储命令源码分析上篇>通过分析memcached的存储命令源码的过程,了解了memcached如何解析文本命令和mencached的内存管理机制 ...

  9. Linux下*.tar.gz文件解压缩命令 find 命令

    1.压缩命令: 命令格式:tar  -zcvf   压缩文件名.tar.gz   被压缩文件名 可先切换到当前目录下.压缩文件名和被压缩文件名都可加入路径. 2.解压缩命令: 命令格式:tar  -z ...

  10. C语言之链表————(转载)

    #include <stdio.h>#include <malloc.h>#define LEN sizeof(struct student) /*-------------- ...