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报文通信(二)报文的封装的更多相关文章
- Java Socket实战之二:多线程通信
转自:http://developer.51cto.com/art/201202/317544.htm 上一篇文章说到怎样写一个最简单的Java Socket通信,但是在上一篇文章中的例子有一个问题就 ...
- java socket通讯(二)处理多个客户端连接
通过java socket通讯(一) 入门示例,就可以实现服务端和客户端的socket通讯,但是上一个例子只能实现一个服务端和一个客户端之间的通讯,如果有多个客户端连接服务端,则需要通过多线程技术来实 ...
- java socket线程通信
关于socket线程通信的一些知识整理 一般我们需要要让两台机子进行通信,需要创建一个Server 类,一个Client类,还需要创建一个线程类 server public class Server ...
- JAVA Socket编程(二)之TCP通信
基于TCP(面向连接)的socket编程,分为客户端和服务器端. 客户端的流程如下: (1)创建套接字(socket) (2)向服务器发出连接请求(connect) (3)和服务器端进行通信(send ...
- Java Socket编程----通信是这样炼成的
Java最初是作为网络编程语言出现的,其对网络提供了高度的支持,使得客户端和服务器的沟通变成了现实,而在网络编程中,使用最多的就是Socket.像大家熟悉的QQ.MSN都使用了Socket相关的技术. ...
- java基础知识回顾之java Socket学习(二)--TCP协议编程
TCP传输(传输控制协议):TCP协议是一种面向连接的,可靠的字节流服务.当客户端和服务器端彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能进行数据的传输.它将一台主机发出的字节流无差错的 ...
- Java Socket应用---通信是这样练成的
网络基础简介 Java 中网络相关 API 的应用 Java 中的 InetAddress 的应用 Test01.java package com.imooc; import java.n ...
- JAVA知识总结(二):封装
时隔近一年,我突然想起来这个文章还没有发完,所以就继续开始写.也不知道自己上次写到哪里了,不管了这里从面向对象的三个特性说起. 类和对象 在这之前,我们先了解什么是对象,已经什么是面向对象?对象:万物 ...
- Java Socket编程基础篇
原文地址:Java Socket编程----通信是这样炼成的 Java最初是作为网络编程语言出现的,其对网络提供了高度的支持,使得客户端和服务器的沟通变成了现实,而在网络编程中,使用最多的就是Sock ...
随机推荐
- The type or namespace name 'Script' does not exist in the namespace 'System.Web' (are you missing an assembly reference?)
应该说是 .net4 的bug,没有所谓的 System.Web.Extensions.dll 库文件,需要将项目的 Target Framework修改为 3.5版本,才能加载System.Web. ...
- mysql 分区表详解
项目中要一张库表实现 list分区.并且支持多种数据库. oracle 很顺利,只是mysql 听说5.1版本就已经支持了, 可是试了很多个版本,都不行,后来查到原因是要5.5 以上版本 分区才支持 ...
- 高仿QQ即时聊天软件开发系列之三登录窗口用户选择下拉框
上一篇高仿QQ即时聊天软件开发系列之二登录窗口界面写了一个大概的布局和原理 这一篇详细说下拉框的实现原理 先上最终效果图 一开始其实只是想给下拉框加一个placeholder效果,让下拉框在未选择未输 ...
- [转]Windows与Linux系统下的库文件介绍
什么是库 库文件是一些预先编译好的函数的集合,那些函数都是按照可再使用的原则编写的.它们通常由一组互相关联的用来完成某项常见工作的函数构成,从本质上来说库是一种可执行代码的二进制形式,可以被操作系 ...
- JavaScript学习笔记(三十八) 复制属性继承
复制属性继承(Inheritance by Copying Properties) 让我们看一下另一个继承模式—复制属性继承(inheritance by copying properties).在这 ...
- mysql 简单的增删改查语句
增加记录: 注:null关键字与auto_increment限制条件相结合,可以为字段自动赋值:字段必须全,且一一对应:字符型用单引号: mysql> insert into test valu ...
- jq:get获取json数据并以表格形式生成到页面
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- PHP扩展开发(6) - VS2012下strncasecmp和fopen函数warning
1. fopen warning C4996: 'fopen': This function or variable may be unsafe. Consider using fopen_s i ...
- notepad++搜索结果不显示line XX的方法
在使用notepad++如果多次搜索,得到的结果中会出现多次line xx: line xx:,造成文件大量垃圾信息的存在,不利于找寻所需的内容,如下图. 对于这种情况, ...
- C 语言字符 和字符串输出
int main(void){ char ch; char str[80]; printf("Input a string: "); //先输入字符串 gets(str);/ ...