TCP服务端,创建了一个线程的接口
public class TCPServer implements Runnable {
private static final String TAG = "TCPServer";
private String chaSet = "UTF-8";
private int port;
private boolean isListen = true;
public TCPServer(int port) {
this.port = port;
}
@Override
public void run() {
try {
ServerSocket serverSocket = new ServerSocket(port);
Log.d(TAG, "run:等待客户端连接... ");
//serverSocket.setSoTimeout(2000);
if (isListen) {
Socket socket = serverSocket.accept();
Log.d(TAG, "run: 客户端已连接");
if (socket != null) {
accept(socket);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
private void accept(Socket socket) {
InputStream is;
OutputStream os;
try {
is = socket.getInputStream();
os = socket.getOutputStream();
int len;
byte[] bytes = new byte[1024 * 4];
while (!socket.isClosed() && !socket.isInputShutdown()) {
while ((len = is.read(bytes)) != -1) {
Log.d(TAG, "accept: len: " + len);
byte[] content = new byte[bytes.length];
System.arraycopy(bytes, 0, content, 0, bytes.length);
String res = new String(content, chaSet);
String trim = res.trim(); //打印的时候去掉多余部分
if (onReceiveListener != null) {
onReceiveListener.receive(trim);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
//创建回调 用于在主线程中监听收消息事件
private onReceiveListener onReceiveListener;
public interface onReceiveListener {
void receive(String bytes);
}
public void setOnReceiveListener(onReceiveListener onReceiveListener) {
this.onReceiveListener = onReceiveListener;
}
}
在主线程中创建线程,调用接口回调监听:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TCPServer tcpServer=new TCPServer(9899);
new Thread(tcpServer).start();
tcpServer.setOnReceiveListener(new TCPServer.onReceiveListener() {
@Override
public void receive(String bytes) {
Log.d(TAG, "receive: bytes: "+bytes);
}
});
}
}
然后用网络调试助手给服务端发消息:
最后记得申请网络请求:
<uses-permission android:name="android.permission.INTERNET"/>
新增需求:定义所需要的数据结构接受数据。
根据定义好的数据结构的长度解析,接受到的bytes然后进行如下处理:
int postX = 0;
int postY = 0;
int size = 0;
int reserveOne = 0;
int reserveTwo = 0;
String reserve = "";
int color = 0;
long pngLen = 0L;
postX = getInt(bytes, 0, 4);
postY = getInt(bytes, 4, 4);
size = getInt(bytes, 8, 4);
reserveOne = getInt(bytes, 12, 4);
reserveTwo = getInt(bytes, 16, 4);
reserve = getString(bytes, 20, 56);
color = getInt(bytes, 76, 4);
pngLen = getInt(bytes, 80, 4);
if (onReceiveListener != null) {
onReceiveListener.receive(postX, postY, size, reserveOne, reserveTwo, reserve, color, pngLen);
//byte转int
public int getInt(byte[] srcBytes, int srcPos, int length) {
byte[] bytes = new byte[length];
System.arraycopy(srcBytes, srcPos, bytes, 0, length);
int anInt = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).getInt();
return anInt;
}
//byte转String
public String getString(byte[] srcBytes, int srcPos, int length) {
byte[] bytes = new byte[length];
System.arraycopy(srcBytes, srcPos, bytes, 0, length);
String str = "解析错误";
try {
str = new String(bytes, 0, length, chaSet);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return str.trim();
}
ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).getInt()
方法的作用是将给定的字节数组 bytes
转换为一个整数值。
首先,ByteBuffer.wrap(bytes)
创建了一个新的字节缓冲区,并将其包装在给定的字节数组 bytes
上。这意味着后续的操作将在该缓冲区上进行。
接下来,.order(ByteOrder.LITTLE_ENDIAN)
设置字节缓冲区的字节顺序为小端序(Little Endian)。字节顺序决定了多字节数据类型在内存中的存储方式,小端序表示低位字节存储在内存的低地址处,高位字节存储在内存的高地址处。
最后,.getInt()
从字节缓冲区中读取四个字节,并将其解释为一个整数值。字节缓冲区的当前位置将被移动四个字节的长度,以便下一次读取操作。
大端小端是什么?询问了chatGPT
大端(Big Endian)和小端(Little Endian)是用于描述多字节数据在内存中的存储方式的两种字节序(byte order)。
在计算机中,多字节数据类型(例如整数、浮点数)通常由多个字节组成。这些字节按照一定的顺序在内存中存储。大端序和小端序指定了这些字节在内存中的排列方式。
-
大端序(Big Endian):在大端序中,最高有效字节(Most Significant Byte,MSB)存储在最低的内存地址处,最低有效字节(Least Significant Byte,LSB)存储在最高的内存地址处。类似于数字书写习惯,高位字节在前,低位字节在后。
-
小端序(Little Endian):在小端序中,最低有效字节(LSB)存储在最低的内存地址处,最高有效字节(MSB)存储在最高的内存地址处。与大端序相反,低位字节在前,高位字节在后。
下面是一个示例,用于说明大端序和小端序的区别:
假设有一个四字节的整数值 0x12345678
(十六进制表示),它在内存中的存储如下:
-
大端序:地址高位->低位
高地址 12 | 34 | 56 | 78 低地址
-
小端序:地址低位->高位
低地址 78 | 56 | 34 | 12 高地址
需要注意的是,大端序和小端序仅在多字节数据类型的存储方面有所区别。对于单字节的数据类型(如字符),字节序没有影响,因为它们只有一个字节。字节序的选择在不同的体系结构和通信协议中具有重要的意义,特别是在跨平台或网络通信时,正确处理字节序是至关重要的。