1.序列化和反序列化:
- 序列化是对象(类的实例)转换成字节数组或者字符串通过网络传输或者存储到本地文件。反序列化:就是将字节数组或字符串在转换成对象实例的过程。
- (因为在网络中传输或者写本地文件,是不能使用对象的,tcp握手之后会建立一个字节流管道传输数据,所以要将对象转换序列化成字节序列)
2.ByteArrayOutputStream、ByteArrayInputStream:
- 这两个流实际就内存流:顾名思义就是将数据写入内存,从内存中读取数据;
- ByteArrayOutputStream:字节数组输出流在内存中创建一个字节数组缓冲区,所有发送到输出流的数 据保存在该字节数组缓冲区中。实际作用就是通过write()将对象各个字段写入一个字节数组,然后在使用toByteArray()将字节数据取出来,通过tcp传输给服务器。
- ByteArrayInputStream:字节数组输入流在内存中创建一个字节数组缓冲区,从输入流读取的数据保存在该字节数组缓冲区中。实际就是将客户端发送过来的消息转成byte数组,存入内存,在分批次读取数据。
代码如下:
- 实例类:
我这里实体类数据类型是这样的:类型和子类型都是1字节,长度是4字节就是一个int,实际数据包含两部分UUID+数据
(代码免费下载链接在最后)
public class Message implements Serializable {public int type; //类型 1字节public int subtype; //子类型 1字节public int dataLength; //数据内容长度 4字节public String uniqueIdentifies; //唯一标识 16字节public String details = ""; //具体内容 N字节public int getType() {return type;}public void setType(int type) {this.type = type;}public int getSubtype() {return subtype;}public void setSubtype(int subtype) {this.subtype = subtype;}public int getDataLength() {return dataLength;}public void setDataLength(int dataLength) {this.dataLength = dataLength;}public String getUniqueIdentifies() {return uniqueIdentifies;}public void setUniqueIdentifies(String uniqueIdentifies) {this.uniqueIdentifies = uniqueIdentifies;}public String getDetails() {return details;}public void setDetails(String details) {this.details = details;}@Overridepublic String toString() {return "Message{" +"type=" + type +", subtype=" + subtype +", dataLength=" + dataLength +", uniqueIdentifies='" + uniqueIdentifies + '\'' +", details='" + details + '\'' +'}';}
}
- 客户端:
public class TcpClient {private String host = "localhost";private int port = 8189;public TcpClient() {}public TcpClient(String host, int port) {this.host = host;this.port = port;}public void chat(){try {Socket socket = new Socket(host,port);ByteArrayOutputStream bArray = new ByteArrayOutputStream();try {DataOutputStream out = new DataOutputStream(socket.getOutputStream());//序列化对象合并写入内存Message message = setMessage();System.out.println(message.details);bArray.write(message.getType());bArray.write(message.getSubtype());byte[] bytes1 = intToByte(message.getDataLength());bArray.write(bytes1,0,bytes1.length);bArray.write(message.uniqueIdentifies.getBytes(), 0, message.uniqueIdentifies.length());//这里分开写中文不会乱码了,如果message.details.getBytes()直接加入的write里会出现中文乱码byte[] bytes2 = message.details.getBytes();bArray.write(bytes2, 0, bytes2.length);bArray.flush();byte[] bytes = bArray.toByteArray();String result = new String(bytes);out.writeUTF(result);}finally {bArray.close();socket.close();}} catch (IOException e) {e.printStackTrace();}}public static void main(String[] args) {new TcpClient().chat();}public Message setMessage(){Message message = new Message();message.setType(0x01);message.setSubtype(0x01);message.setDetails("春❥(^_-)");message.setDataLength(16+message.getDetails().length());//16字节的UUID随便编的或者自己写个方法造也行(或者API注意16个字节,如果是多个字节需要自行修改服务器参数)message.setUniqueIdentifies(new String("WHDISakcmqSiamSq"));return message;}//将int转换成四字节public byte[] intToByte(int res) {byte[] targets = new byte[4];targets[0] = (byte) (res & 0xff);// 最低位targets[1] = (byte) ((res >> 8) & 0xff);// 次低位targets[2] = (byte) ((res >> 16) & 0xff);// 次高位targets[3] = (byte) (res >>> 24);// 最高位,无符号右移。return targets;}
}
- 服务器:
package org2.server;import org2.message.Message;import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;/*** @author Chun* @create 2020-07-30 15:24**/
public class TcpServer {private int port = 8189;public TcpServer() {}public TcpServer(int port) {this.port = port;}public void service() {try {ServerSocket serverSocket = new ServerSocket(port);Socket socket = serverSocket.accept();ByteArrayInputStream bInArray = null;try {DataInputStream in = new DataInputStream(socket.getInputStream());String s = in.readUTF();byte[] bytes = s.getBytes();int realLength = bytes.length;System.out.println("realLength:" + realLength);bInArray = new ByteArrayInputStream(bytes);Message message = new Message();message.setType(bInArray.read());message.setSubtype(bInArray.read());byte[] bytesDataLength = new byte[4];bInArray.read(bytesDataLength, 0, 4);int i = byteToInt(bytesDataLength);message.setDataLength(i);byte[] byteUniqueIdentifies = new byte[16];bInArray.read(byteUniqueIdentifies, 0, 16);message.setUniqueIdentifies(new String(byteUniqueIdentifies));byte[] byteDetails = new byte[realLength - 22];bInArray.read(byteDetails, 0, realLength - 22);message.setDetails(new String(byteDetails));System.out.println(message);} finally {socket.close();serverSocket.close();}} catch (IOException e) {e.printStackTrace();}}public int byteToInt(byte[] arr) {int i0 = (int) ((arr[0] & 0xff) << 0 * 8);int i1 = (int) ((arr[1] & 0xff) << 1 * 8);int i2 = (int) ((arr[2] & 0xff) << 2 * 8);int i3 = (int) ((arr[3] & 0xff) << 3 * 8);return i0 + i1 + i2 + i3;}public static void main(String[] args) {new TcpServer().service();}
}
TcpClient.java 下载
Message.java 下载
TcpServer.java 下载