说下问题吧,我现在想用java去做一个基于TCP通讯的客户端,服务端是C++实现的,我们通讯的数据包是自己定义的私有格式,
因为C++有指针可以用,所以封包解包都是小菜菜。现在想用java来实现打包解包的操作。
我的私有包头是这样定义的:
public class HeaderStruct {
public int length;
public int seq;
public byte[] src_type = new byte[1];
public byte[] terminal = new byte[20];
public int to_flow;
public byte[] msg_type = new byte[1];
public int msgid;
}
那么这个包头总共是38字节,包头之后拼接数据,数据是String类型的。
现在需要把数据拼装好然后调用socket的接口将数据发送出去,过程就这样。
解包的话也是从包头开始解,比如第一个先解出4字节的数据,表示长度,然后偏移4字节解出seq,一次类推。
因为java里面没有指针,所以对内存操作起来很费劲,我也不知道能不能进行内存拷贝,我试着写了一些代码,但发现完全不行,也可能是我的用法不对吧,如下:
public class pack {
public byte[] PackHeader(HeaderStruct hs)
{
byte[] header = new byte[38];
//byte[] bt = ByteBuffer.allocate(4).putInt(hs.length).array();
//byte[] bt2 = intToByteArray(hs.length);
System.arraycopy(header, 0, ByteBuffer.allocate(4).putInt(hs.length).array(), 0, 4);
System.arraycopy(header, 3, ByteBuffer.allocate(4).putInt(hs.seq).array(), 0, 4);
System.arraycopy(header, 7, hs.src_type, 0, 1);
System.arraycopy(header, 8, hs.terminal, 0, 20);
System.arraycopy(header, 28, ByteBuffer.allocate(4).putInt(hs.to_flow).array(), 0, 4);
System.arraycopy(header, 32, hs.msg_type, 0, 1);
System.arraycopy(header, 33, ByteBuffer.allocate(4).putInt(hs.msgid).array(), 0, 4);
return header;
}
private byte[] intToByteArray (final int integer) {
int byteNum = (40 - Integer.numberOfLeadingZeros (integer < 0 ? ~integer : integer)) / 8;
byte[] byteArray = new byte[4];
for (int n = 0; n < byteNum; n++)
byteArray[3 - n] = (byte) (integer >>> (n * 8));
return (byteArray);
}
public static void main(String[] args)
{
pack pk = new pack();
HeaderStruct hs = new HeaderStruct();
hs.length = 100;
hs.seq = 1;
hs.msgid = 1001;
byte[] header = pk.PackHeader(hs);
for(byte t : header)
{
System.out.format("0X%x\n", t);
}
}
}
打印出来全是0
5 个解决方案
#1
System.arraycopy 是我把这个方法的参数搞反了,调换一下位置就OK了
C里面的copy函数都是被拷贝的值都是放在后面的,没想到JAVA是放前面,坑爹啊
C里面的copy函数都是被拷贝的值都是放在后面的,没想到JAVA是放前面,坑爹啊
#2
不需要copy来copy去的。稍等会吧,我发段代码给你
#3
自定义数据包,无论自定义为何种结构。最终进行通信时,无非就是字节数据的传递。只在客户只需要将对应数据进行编码转为对应的byte数组,最终传递给服务端,由服务端进行解码操作。这点相信楼主也很清楚了。客户端编码这块,楼主可以参考下以下代码,有疑问可以追问。
import com.sun.xml.internal.ws.api.message.Packet;
import java.nio.ByteBuffer;
/**
* @author zhuangqing
*/
public class DataEncodeTest {
public static void main(String[] args) {
DataPacket packet = new DataPacket();
packet.header = new HeaderStruct();
packet.data = "test";
//最终要发送给服务端的数据
byte[] sendData = packet.toBytes();
System.out.println(sendData.length);
}
}
/**
* 协议包
*/
class DataPacket {
public HeaderStruct header;
public String data;
public byte[] toBytes() {
byte[] strData = data.getBytes();
int dataSize = HeaderStruct.DATA_SIZE + 4 + strData.length;
ByteBuffer buffer = ByteBuffer.allocate(dataSize);
buffer.put(header.toBytes());
buffer.putInt(strData.length);
buffer.put(strData);
return buffer.array();
}
}
/**
* 包头描述
*/
class HeaderStruct {
public int length;
public int seq;
public byte[] src_type = new byte[1];
public byte[] terminal = new byte[20];
public int to_flow;
public byte[] msg_type = new byte[1];
public int msgid;
/**
* 4(length)+4(seq)+4(一个int值存src_type.length)+1(src_type all data) + ... + 4(msgid)
* 共7个int + 1b + 20b + 1b
*/
public static final int DATA_SIZE = 7 * 4 + 1 + 20 + 1;
public byte[] toBytes() {
ByteBuffer buffer = ByteBuffer.allocate(HeaderStruct.DATA_SIZE);
buffer.putInt(length);
buffer.putInt(seq);
buffer.putInt(src_type.length);
buffer.put(src_type);
buffer.putInt(terminal.length);
buffer.put(terminal);
buffer.putInt(to_flow);
buffer.putInt(msg_type.length);
buffer.put(msg_type);
buffer.putInt(msgid);
return buffer.array();
}
}
#4
JAVA也有字符串定位和位移的
JAVA里只是不能显示地使用指针而已,但根据地址操作无处不在。
JAVA里只是不能显示地使用指针而已,但根据地址操作无处不在。
#5
自己写代码打包解包有点麻烦,我最近也在做TCP,可以加扣交流下的
#1
System.arraycopy 是我把这个方法的参数搞反了,调换一下位置就OK了
C里面的copy函数都是被拷贝的值都是放在后面的,没想到JAVA是放前面,坑爹啊
C里面的copy函数都是被拷贝的值都是放在后面的,没想到JAVA是放前面,坑爹啊
#2
不需要copy来copy去的。稍等会吧,我发段代码给你
#3
自定义数据包,无论自定义为何种结构。最终进行通信时,无非就是字节数据的传递。只在客户只需要将对应数据进行编码转为对应的byte数组,最终传递给服务端,由服务端进行解码操作。这点相信楼主也很清楚了。客户端编码这块,楼主可以参考下以下代码,有疑问可以追问。
import com.sun.xml.internal.ws.api.message.Packet;
import java.nio.ByteBuffer;
/**
* @author zhuangqing
*/
public class DataEncodeTest {
public static void main(String[] args) {
DataPacket packet = new DataPacket();
packet.header = new HeaderStruct();
packet.data = "test";
//最终要发送给服务端的数据
byte[] sendData = packet.toBytes();
System.out.println(sendData.length);
}
}
/**
* 协议包
*/
class DataPacket {
public HeaderStruct header;
public String data;
public byte[] toBytes() {
byte[] strData = data.getBytes();
int dataSize = HeaderStruct.DATA_SIZE + 4 + strData.length;
ByteBuffer buffer = ByteBuffer.allocate(dataSize);
buffer.put(header.toBytes());
buffer.putInt(strData.length);
buffer.put(strData);
return buffer.array();
}
}
/**
* 包头描述
*/
class HeaderStruct {
public int length;
public int seq;
public byte[] src_type = new byte[1];
public byte[] terminal = new byte[20];
public int to_flow;
public byte[] msg_type = new byte[1];
public int msgid;
/**
* 4(length)+4(seq)+4(一个int值存src_type.length)+1(src_type all data) + ... + 4(msgid)
* 共7个int + 1b + 20b + 1b
*/
public static final int DATA_SIZE = 7 * 4 + 1 + 20 + 1;
public byte[] toBytes() {
ByteBuffer buffer = ByteBuffer.allocate(HeaderStruct.DATA_SIZE);
buffer.putInt(length);
buffer.putInt(seq);
buffer.putInt(src_type.length);
buffer.put(src_type);
buffer.putInt(terminal.length);
buffer.put(terminal);
buffer.putInt(to_flow);
buffer.putInt(msg_type.length);
buffer.put(msg_type);
buffer.putInt(msgid);
return buffer.array();
}
}
#4
JAVA也有字符串定位和位移的
JAVA里只是不能显示地使用指针而已,但根据地址操作无处不在。
JAVA里只是不能显示地使用指针而已,但根据地址操作无处不在。
#5
自己写代码打包解包有点麻烦,我最近也在做TCP,可以加扣交流下的