昨天我们谈了怎么建立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. Oracle数据库中的blob类型解析

    Oracle的Blob字段比较特殊,他比long字段的性能要好很多,可以用来保存例如图片之类的二进制数据. 写入Blob字段和写入其它类型字段的方式非常不同,因为Blob自身有一个cursor,你必须 ...

  2. sqlite--代码操作

    1.创建数据库 NSString * docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainM ...

  3. Swift中可能失败的构造器的传播(调用)和重写

    import Foundation /* 可能失败构造器的传播(调用) 1.可能失败的构造器可以调用同一个类中的普通构造器 2.普通构造器不能调用同一个类中的可能失败构造器 3.结构体中, 普通构造器 ...

  4. Java Se 基础系列(笔记) -- OO

    记录所学到的关于Java Se的一些基础知识 1.对象是通过“属性(成员变量)”和“方法”来分别对应事物所具有的静态属性和动态属性 2.类(Class)是对某一类事物的抽象,对象(Object)为某个 ...

  5. hdu5353

    模拟,,, 每个人有一些糖果,每两个人之间只能给一个糖果,问最后是否能让所有人的糖果数量相同,只要确定一个糖果的流向其他的就能够确定. 马虎了,卡了好几天,心塞塞的... #include<io ...

  6. linux一些常用指令整理

    set number:设置行号 set list:区分tab和空格 按w:一个字一个字跳转 按b:一个字一个字回跳 shift+6:行首 shift+4:行尾 ctrl+v:选中块,再按shift+i ...

  7. Oracle—用户管理的备份(二)

    在用户管理的备份(一)中(详见:Oracle—用户管理的备份)对用户管理备份几种情况进行了说明:接下来说明几种特别情况和DBverify的使用. 一.如果在表空间在备份模式下,主机发生了异常关闭,会出 ...

  8. android studio如何查看数据库文件

    android studio查看数据库文件有两种方式: 1.SQLSCOUT 优点:集成在as中,功能强大. 缺点:收费,破解麻烦. 2.Android Device Monitor 中的File E ...

  9. LinkButton中添加删除确认框

    LinkButton1.Attributes.Add("onclick", "javascript:return confirml('确认删除?');");

  10. map关联容器

    #include<map> map<k, v> m; 创建一个名为 m 的空 map 对象,其键和值的类型分别为 k 和 v map<k, v>m(m2);创建 m ...