背景:在学习socket定长消息的时候遇到了几个问题,这里总结一下
public class SocketServer {
public static void main(String[] args) throws Exception {
// 监听指定的端口
int port = 55533;
ServerSocket server = new ServerSocket(port);
// server将一直等待连接的到来
System.out.println("server将一直等待连接的到来");
Socket socket = server.accept();
// 建立好连接后,从socket中获取输入流,并建立缓冲区进行读取
InputStream inputStream = socket.getInputStream();
byte[] bytes;
// 因为可以复用Socket且能判断长度,所以可以一个Socket用到底
while (true) {
// 首先读取两个字节表示的长度
int first = inputStream.read();
//如果读取的值为-1 说明到了流的末尾,Socket已经被关闭了,此时将不能再去读取
if(first==-1){
break;
}
int second = inputStream.read();
int length = (first << 8) + second;
// 然后构造一个指定长的byte数组
bytes = new byte[length];
// 然后读取指定长度的消息即可
inputStream.read(bytes);
System.out.println("get message from client: " + new String(bytes, "UTF-8"));
}
inputStream.close();
socket.close();
server.close();
}
}
public class SocketClient {
public static void main(String args[]) throws Exception {
// 要连接的服务端IP地址和端口
String host = "127.0.0.1";
int port = 55533;
// 与服务端建立连接
Socket socket = new Socket(host, port);
// 建立连接后获得输出流
OutputStream outputStream = socket.getOutputStream();
String message = "你好 yiwangzhibujian";
//首先需要计算得知消息的长度
byte[] sendBytes = message.getBytes("UTF-8");
//然后将消息的长度优先发送出去
outputStream.write(sendBytes.length >>8);
outputStream.write(sendBytes.length);
//然后将消息再次发送出去
outputStream.write(sendBytes);
outputStream.flush();
//==========此处重复发送一次,实际项目中为多个命名,此处只为展示用法
message = "第二条消息";
sendBytes = message.getBytes("UTF-8");
outputStream.write(sendBytes.length >>8);
outputStream.write(sendBytes.length);
outputStream.write(sendBytes);
outputStream.flush();
//==========此处重复发送一次,实际项目中为多个命名,此处只为展示用法
message = "the third message!";
sendBytes = message.getBytes("UTF-8");
outputStream.write(sendBytes.length >>8);
outputStream.write(sendBytes.length);
outputStream.write(sendBytes);
outputStream.close();
socket.close();
}
}
这里的代码转自https://blog.youkuaiyun.com/roy_70/article/details/72519189
问题:
代码中为什么要发送两次,第一次的右移八位的作用是什么
原因:
定长发送数据,我们首先要将数据的长度发送给服务端。因为write是按字节发送的,如果为Integer类型的话,会强转成byte类型,只保留最低的这里发送八位,所以为了保证数据的完整性,我们需要将长度分成字节大小。一个Int类型等于四个字节,至于为什么发送两个字节,作者说:“一般呢,如果用作命名发送,两个字节就够了,如果还不放心4个字节基本就能满足你的所有要求”。
那么发送的两次有什么不同呢,第一次的将int的第8到16位挪到了第0到8位上,然后转byte类型的时候就可以将8到16位的值发送过去。其实本质上就是将int类型拆分成四个字节发送,然后服务端在将四个字节拼接成int类型。
问题:
流的read()方法返回的int类型的值有什么用
回答:
返回值是用来标识流结尾的,当返回值为-1时,说明socket已经被关闭,不能再去读取了
无参数的read方法,读取的数据其实也就时int类型的返回值