SocketChannel:读取的字节数不足
SocketChannel: not enough bytes read
我正在通过 socketChannel 实现客户端服务器通信。在对较大对象进行负载测试期间,我 运行 遇到了客户端问题。
所以我已经实施了一个测试程序来验证我的问题并在此处进行说明。
首先是一个小的解释:我不知道在客户端将通过套接字发送的对象的大小。
所以我把我的发送分成两部分:
1.:在服务器端将对象序列化为字节缓冲区(在用字节数组说明的示例中)。
2.:通过socket发送对象的soze
3.: 发送对象
在客户端,我首先读取一个 4 字节的 ByteBuffer 中的对象大小。其次,我创建了一个具有读取大小的新 ByteBuffer,然后将数据从 socketchannel 读取到缓冲区中。
如果你看一下代码,你会看到(在客户端 class),我的期望是,socketChannel.read 方法将 return 相同字节数为之前读取的对象大小。
但是增加sendet byte array后,会出现大量的不匹配和零大小。为什么会这样??套接字通道是非阻塞的。所以它应该能够读取配置的字节缓冲区中的所有内容。字节缓冲区的大小足够大。那么为什么有时会丢失字节?
非常感谢!
这是示例代码:
主要Class
package socketChannelMaxTest;
import java.io.IOException;
public class MaxTest {
public static void main(String[] args) throws IOException {
Sender.startServer();
new Client();
}
}
服务器发件人
package socketChannelMaxTest;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
public class Sender {
private SocketChannel sc;
public Sender(SocketChannel sc) {
this.sc = sc;
startThreads();
}
public static void startServer() throws IOException {
ServerSocketChannel ssc = ServerSocketChannel.open();
ServerSocketChannel socket = ssc.bind(new InetSocketAddress(9999));
new Thread(() -> {
System.out.println("Server: Listening");
SocketChannel sc;
try {
sc = socket.accept();
sc.configureBlocking(true);
new Sender(sc);
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
private void startThreads() {
new Thread(() -> {
System.out.println("Sender: start sending");
ByteBuffer headerBuffer = ByteBuffer.allocateDirect(4);
int maxBufferSize = 10*1024;
for (int i = 1; i < maxBufferSize; i++) {
byte[] randomByteArray = new byte[i];
ByteBuffer dataBuffer = ByteBuffer.wrap(randomByteArray);
int objectSize = randomByteArray.length;
headerBuffer.putInt(objectSize);
headerBuffer.flip();
try {
sc.write(headerBuffer);
System.out.println("Sender: " + objectSize + " " + sc.write(dataBuffer));
} catch (IOException e) {
e.printStackTrace();
}
headerBuffer.compact();
}
System.out.println("Sender: finished");
}, "Receiver Thread").start();
}
}
客户端接收方
package socketChannelMaxTest;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
public class Client {
public Client() throws IOException {
startThreads();
}
private void startThreads() throws IOException {
System.out.println("Client: start client");
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("localhost", 9999));
socketChannel.configureBlocking(true);
System.out.println("Client: connected");
new Thread(() -> {
System.out.println("Client: start listening");
ByteBuffer headerBuffer = ByteBuffer.allocate(4);
int readedObjectSize = 0;
while (socketChannel.isConnected()) {
try {
int read = socketChannel.read(headerBuffer);
headerBuffer.flip();
readedObjectSize = headerBuffer.getInt();
headerBuffer.compact();
ByteBuffer dataBuffer = ByteBuffer.allocateDirect(readedObjectSize);
int readedDataBufferSize = socketChannel.read(dataBuffer);
// should be 0
int remainginBytes = dataBuffer.remaining();
dataBuffer.flip();
System.out.println("Client:" + readedObjectSize + " " + readedDataBufferSize + " " + remainginBytes);
if (readedObjectSize != readedDataBufferSize)
System.out.println("Missmatch");
} catch (Exception e1) {
e1.printStackTrace();
}
}
}, "Receiver Thread").start();
}
}
您假设剩余数据在任何时候都始终为 0 的事实存在问题
// should be 0
int remainginBytes = dataBuffer.remaining();
您无法确定任何时候都会是这种情况。如果数据太大,您将需要从 SocketChannel 中再次读取以检索剩余信息。
你应该有一个从 socketChannel 读取直到没有剩余字节的循环
int read = socketChannel.read(headerBuffer);
headerBuffer.flip();
readedObjectSize = headerBuffer.getInt();
headerBuffer.compact();
int remainginBytes = -1;
int readedDataBufferSize = 0;
ByteBuffer dataBuffer = ByteBuffer.allocateDirect(readedObjectSize);
while(remainginBytes != 0){
readedDataBufferSize = socketChannel.read(dataBuffer);
remainginBytes = dataBuffer.remaining();
}
dataBuffer.flip();
System.out.println("Client:" + readedObjectSize + " " + readedDataBufferSize + " " + remainginBytes);
if (readedObjectSize != readedDataBufferSize)
System.out.println("Missmatch");
请记住,将套接字配置为 non-blocking 模式并不能确保您在检索所有数据之前不会 return
如果这仍然不适合您,请随时发表评论!
我正在通过 socketChannel 实现客户端服务器通信。在对较大对象进行负载测试期间,我 运行 遇到了客户端问题。 所以我已经实施了一个测试程序来验证我的问题并在此处进行说明。
首先是一个小的解释:我不知道在客户端将通过套接字发送的对象的大小。 所以我把我的发送分成两部分: 1.:在服务器端将对象序列化为字节缓冲区(在用字节数组说明的示例中)。 2.:通过socket发送对象的soze 3.: 发送对象
在客户端,我首先读取一个 4 字节的 ByteBuffer 中的对象大小。其次,我创建了一个具有读取大小的新 ByteBuffer,然后将数据从 socketchannel 读取到缓冲区中。
如果你看一下代码,你会看到(在客户端 class),我的期望是,socketChannel.read 方法将 return 相同字节数为之前读取的对象大小。
但是增加sendet byte array后,会出现大量的不匹配和零大小。为什么会这样??套接字通道是非阻塞的。所以它应该能够读取配置的字节缓冲区中的所有内容。字节缓冲区的大小足够大。那么为什么有时会丢失字节?
非常感谢! 这是示例代码:
主要Class
package socketChannelMaxTest;
import java.io.IOException;
public class MaxTest {
public static void main(String[] args) throws IOException {
Sender.startServer();
new Client();
}
}
服务器发件人
package socketChannelMaxTest;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
public class Sender {
private SocketChannel sc;
public Sender(SocketChannel sc) {
this.sc = sc;
startThreads();
}
public static void startServer() throws IOException {
ServerSocketChannel ssc = ServerSocketChannel.open();
ServerSocketChannel socket = ssc.bind(new InetSocketAddress(9999));
new Thread(() -> {
System.out.println("Server: Listening");
SocketChannel sc;
try {
sc = socket.accept();
sc.configureBlocking(true);
new Sender(sc);
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
private void startThreads() {
new Thread(() -> {
System.out.println("Sender: start sending");
ByteBuffer headerBuffer = ByteBuffer.allocateDirect(4);
int maxBufferSize = 10*1024;
for (int i = 1; i < maxBufferSize; i++) {
byte[] randomByteArray = new byte[i];
ByteBuffer dataBuffer = ByteBuffer.wrap(randomByteArray);
int objectSize = randomByteArray.length;
headerBuffer.putInt(objectSize);
headerBuffer.flip();
try {
sc.write(headerBuffer);
System.out.println("Sender: " + objectSize + " " + sc.write(dataBuffer));
} catch (IOException e) {
e.printStackTrace();
}
headerBuffer.compact();
}
System.out.println("Sender: finished");
}, "Receiver Thread").start();
}
}
客户端接收方
package socketChannelMaxTest;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
public class Client {
public Client() throws IOException {
startThreads();
}
private void startThreads() throws IOException {
System.out.println("Client: start client");
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("localhost", 9999));
socketChannel.configureBlocking(true);
System.out.println("Client: connected");
new Thread(() -> {
System.out.println("Client: start listening");
ByteBuffer headerBuffer = ByteBuffer.allocate(4);
int readedObjectSize = 0;
while (socketChannel.isConnected()) {
try {
int read = socketChannel.read(headerBuffer);
headerBuffer.flip();
readedObjectSize = headerBuffer.getInt();
headerBuffer.compact();
ByteBuffer dataBuffer = ByteBuffer.allocateDirect(readedObjectSize);
int readedDataBufferSize = socketChannel.read(dataBuffer);
// should be 0
int remainginBytes = dataBuffer.remaining();
dataBuffer.flip();
System.out.println("Client:" + readedObjectSize + " " + readedDataBufferSize + " " + remainginBytes);
if (readedObjectSize != readedDataBufferSize)
System.out.println("Missmatch");
} catch (Exception e1) {
e1.printStackTrace();
}
}
}, "Receiver Thread").start();
}
}
您假设剩余数据在任何时候都始终为 0 的事实存在问题
// should be 0
int remainginBytes = dataBuffer.remaining();
您无法确定任何时候都会是这种情况。如果数据太大,您将需要从 SocketChannel 中再次读取以检索剩余信息。
你应该有一个从 socketChannel 读取直到没有剩余字节的循环
int read = socketChannel.read(headerBuffer);
headerBuffer.flip();
readedObjectSize = headerBuffer.getInt();
headerBuffer.compact();
int remainginBytes = -1;
int readedDataBufferSize = 0;
ByteBuffer dataBuffer = ByteBuffer.allocateDirect(readedObjectSize);
while(remainginBytes != 0){
readedDataBufferSize = socketChannel.read(dataBuffer);
remainginBytes = dataBuffer.remaining();
}
dataBuffer.flip();
System.out.println("Client:" + readedObjectSize + " " + readedDataBufferSize + " " + remainginBytes);
if (readedObjectSize != readedDataBufferSize)
System.out.println("Missmatch");
请记住,将套接字配置为 non-blocking 模式并不能确保您在检索所有数据之前不会 return
如果这仍然不适合您,请随时发表评论!