byte数组问题

sunjianbo1126 2012-08-29 11:10:21
tcp报文格式定义如下:
Head Type Length Data
Head:消息头,2个字节,固定为0x1F1F。
Type:消息类型,1个字节:
 0x1:身份认证
 0x2:心跳信息
 0x3:能耗数据
Length:4个字节,Integer整型,指明消息体Data长度,采用网络字节顺序(高位字节在前)。
Data:应用层数据包,明文或是经过AES加密后的数据,原始数据是变长字符串,xml

我用的socket接收数据,将报文存放到一个byte[]中

问题:
1.0x1如何接收?byte b='0x1'不行的,0x1不是三个字节吗?
2.如果取得length这四个字节,如何计算出data长度啊
3.能不能给个报文的例子啊,我想测试下,我用socket编程,客户端传过来,服务端解析

...全文
344 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
zgl21222 2012-08-30
  • 打赏
  • 举报
回复
获取数据 推荐用这个方法String(byte[] bytes, int offset, int length)

比如获取:length , 则 String length = new String(buff,3,4); //从下标为3开始,长度为4
得到字符串后再转换为int 或其它类型就比较容易了
zgl21222 2012-08-30
  • 打赏
  • 举报
回复
获取数据 推荐用这个方法String(byte[] bytes, int offset, int length)

比如获取:length , 则 String length = new String(buff,3,4); //从下标为3开始,长度为4
得到字符串后再转换为int 或其它类型就比较容易了
zgl21222 2012-08-30
  • 打赏
  • 举报
回复
1。接受端:接受传过来的字节流到buff字节数组中
byte[] buff =new byte[1024];//定义二进制缓存
bis=new BufferedInputStream(is);//这里开始接收二进制数据流
while(true){//循环接收二进制数据流
int len = bis.read(buff);//读出接收到的二进制流,放入缓存buff,返回本次接收到的二进制流的长度,若长度为零,返回-1
if(-1==len){//len==-1,没流再来了,结束
break;
}

2。获取想要的数据

Head Type Length Data
Head:消息头,2个字节,固定为0x1F1F。
Type:消息类型,1个字节:
 0x1:身份认证
 0x2:心跳信息
 0x3:能耗数据
Length:4个字节,Integer整型,指明消息体Data长度,采用网络字节顺序(高位字节在前)。
Data:应用层数据包,明文或是经过AES加密后的数据,原始数据是变长字符串,xml

根据定义的报文,
head肯定为:byte[] head = new byte[2];
head[0]=buffer[0];
head[1]=buffer[1];

String head_s = new head_s(head);
打印出来head_s肯定为头得字符串信息,当然你也可以转换为其它类型


byte[] type= new byte[1];
type[0]=buff[2];


至于byte[]怎么转换为int 或 char等 应该不难了

sunjianbo1126 2012-08-29
  • 打赏
  • 举报
回复
ldh911 大侠 能给我个tcp报文的例子吗 ,我想测试下,我socket编程,在客户端输进去,服务器端解析
MiceRice 2012-08-29
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 的回复:]
is.read()的时候会跳过原来读取过的数据吗?
[/Quote]

InputStream 是流,除非你做了特殊处理,否则数据只能被读取一次,流只会向前滚动。
sunjianbo1126 2012-08-29
  • 打赏
  • 举报
回复
is.read(packHead);
.....
is.read(packType);
.....
is.read(packLen);
.....
is.read()的时候会跳过原来读取过的数据吗?
MiceRice 2012-08-29
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 的回复:]
如何取4个byte啊,byte[1]+byte[2]+byte[3]+byte[4]吗?
[/Quote]

参见三楼代码,核心就两句话:
byte[] packLen = new byte[4];
is.read(packLen); // 读取长度后可以用1楼的建议来转成int
int len = byteArrayToInt(packLen, 0); // 这个是调用1楼提供的函数(话说写的有点点复杂)
scbb 2012-08-29
  • 打赏
  • 举报
回复
上面的链接不能访问的话
http://javapub.iteye.com/blog/665696
scbb 2012-08-29
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 的回复:]

2.把4个byte取到后,用下面的函数转成int

Java code


public static int byteArrayToInt(byte[] b, int offset) {
int value= 0……
[/Quote]

如何取4个byte啊,byte[1]+byte[2]+byte[3]+byte[4]吗?
[/Quote]

Socket使用时,会拿到一个InputStream。
然后可以通过InputStream拿到byte[]。
http://javapub.iteye.com/blog/665696 参考。

byteArrayToInt的第2个参数int offset就是偏移量。
比如你的byte数组长度会N, 而你想从第4位取后面4个转成int。
(你的例子里正好就是第4位开始后面是length)

int length = byteArrayToInt(byteArray, 3); //取第四位,后4个byte转成int

sunjianbo1126 2012-08-29
  • 打赏
  • 举报
回复
2.把4个byte取到后,用下面的函数转成int

Java code


public static int byteArrayToInt(byte[] b, int offset) {
int value= 0……
[/Quote]

如何取4个byte啊,byte[1]+byte[2]+byte[3]+byte[4]吗?
MiceRice 2012-08-29
  • 打赏
  • 举报
回复
0x1 是16进制书写格式,实际上就是十进制的 1

byte b = 0x1; 或者 byte b = 1;

读取这种数据包型的数据时建议你用byte数组进行批量读取,比如先定义:
  byte[] packHead = new byte[2];
byte[] packType = new byte[1];
byte[] packLen = new byte[4];
然后就直接三句话连续读取(is 就是指 socket.getInputStream()所得到的输入流):
  is.read(packHead); 
// 需要的话还可以检查下head信息是否正确
if (packHead[0] != 0x1f || packHead[1] != 0x1f) throw new RuntimeException("头信息错误");

is.read(packType);
// 可以用switch进行分支判断
switch(packType[0]) {
case (byte)0x1:
...
break;
case (byte)0x2:
...
break;
case (byte)0x3:
...
break;
default:
throw new RuntimeException("类型信息错误" + packType[0]);
}

is.read(packLen); // 读取长度后可以用1楼的建议来转成int
scbb 2012-08-29
  • 打赏
  • 举报
回复
3.能不能给个报文的例子啊,我想测试下,我用socket编程,客户端传过来,服务端解析
我也百度了,没有特别好的例子呀。。
给你个方向吧。

先用 Java Socket 关键字找Socket通信的例子。 很多都是接受文件或者字符串的。
然后再找 Java 二进制 分析 关键字找 java读和解析二进制的例子。
scbb 2012-08-29
  • 打赏
  • 举报
回复
1.0x1如何接收?byte b='0x1'不行的,0x1不是三个字节吗?
byte b=0x1; 这样编译通过
0x1是1个字节。

2.把4个byte取到后,用下面的函数转成int

public static int byteArrayToInt(byte[] b, int offset) {
int value= 0;
for (int i = 0; i < 4; i++) {
int shift= (4 - 1 - i) * 8;
value +=(b[i + offset] & 0x000000FF) << shift;
}
return value;
}

使用

byte[] byteArray = new byte[] { 0, 0, 1, 0 };
System.out.println(byteArrayToInt(byteArray, 0));
scbb 2012-08-29
  • 打赏
  • 举报
回复
嘿嘿,你贴你的代码吧。
还有上面说的错误是内存溢出了。
sunjianbo1126 2012-08-29
  • 打赏
  • 举报
回复
packHead:[B@e53108
packType:[B@f62373
packLen:[B@19189e1
len:50348354
packData:[B@1690726
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
我都严格按照你说的写了,结果怎么是这个啊 应该len:3 packData:ABC吧
MiceRice 2012-08-29
  • 打赏
  • 举报
回复
这个报文直接写就行了:
byte[] packSend = {0x1F, 0x1F, 0x1, 0x3, 0x0, (byte)'A', (byte)'B', (byte)'C' };
意思就是 Type是0x1;Length长度是3;然后三个字节的明文数据ABC

Socket连接好服务端后:
Socket socket = new Socket("localhost", 端口); // 连接服务端
OutputStream os = socket.getOutputStream(); // 获取发送流
os.write(packSend); // 就一个包全发出去了

就这么简单了。

sunjianbo1126 2012-08-29
  • 打赏
  • 举报
回复
[Quote=引用楼主 的回复:]
tcp报文格式定义如下:
Head Type Length Data
Head:消息头,2个字节,固定为0x1F1F。
Type:消息类型,1个字节:
 0x1:身份认证
 0x2:心跳信息
 0x3:能耗数据
Length:4个字节,Integer整型,指明消息体Data长度,采用网络字节顺序(高位字节在前)。
Data:应用层数据包,明文或是经过AES加密后的数据,原始数……
[/Quote]
就是这样的一个报文
MiceRice 2012-08-29
  • 打赏
  • 举报
回复
啥叫。。。TCP报文的例子。。。

你有没有曾经写过Socket通讯?如果没有,那就需要看比较基础的内容。

如果有就简单点。

这是一个文本消息通讯的例子(不是二进制流),服务端:

import java.io.*;
import java.net.*;
import java.util.*;

public class EchoServer {
public static final int PORT = 10000;

public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(PORT);
try {
while (true) {
System.out.println("服务端就绪,等待客户端连接");

// 侦听并接受到此套接字的连接。此方法在进行连接之前一直阻塞。
Socket socket = serverSocket.accept();
System.out.println("有客户端连接上来了,已建立Socket链接");

EchoServerWorker worker = new EchoServerWorker(socket);
System.out.println("启动工作线程");
new Thread(worker).start();
}
} finally {
serverSocket.close();
}
}
}

class EchoServerWorker implements Runnable {
private Socket socket; // 工作线程所服务的目标Socket

EchoServerWorker(Socket socket) {
this.socket = socket;
}

public void run() {
try {
try {
// 准备输入输出端口
Scanner sc = new Scanner(socket.getInputStream());
OutputStreamWriter out = new OutputStreamWriter(socket.getOutputStream());
System.out.println("Socket for " + socket.getPort() + " started.");

// 读取信息并直接返回,这里按行读取(\n)
String str;
while ((str = sc.nextLine()) != null) {
System.out.println("【From Client】" + str);
out.write(str + "\n");
out.flush();
}
} finally {
socket.close();
System.out.println("Scoket for " + socket.getPort() + " closed.");
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}



客户端:
import java.io.*;
import java.net.*;
import java.util.*;

public class EchoClient {
public static final int PORT = 10000;

public static void main(String[] args) throws Exception {
Socket socket = new Socket("localhost", PORT);
Scanner sc = new Scanner(socket.getInputStream());
OutputStreamWriter out = new OutputStreamWriter(socket.getOutputStream());
int counter = 0;
while (true) {
out.write("Client: " + counter++ + "\n");
out.flush();
String back = sc.nextLine();
System.out.println("【From Server】" + back);
Thread.sleep(1000);
}
}

}

67,512

社区成员

发帖
与我相关
我的任务
社区描述
J2EE只是Java企业应用。我们需要一个跨J2SE/WEB/EJB的微容器,保护我们的业务核心组件(中间件),以延续它的生命力,而不是依赖J2SE/J2EE版本。
社区管理员
  • Java EE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧