我通过socketChannel实现客户端服务器通信。在使用较大的objets进行负载测试期间,我遇到了客户端问题。 所以我已经实施了一个测试程序来验证我的问题,并在此处进行说明。
首先是一个小解释:我不知道客户端将通过套接字发送的对象的大小。 所以我将发送分为两部分: 1:将对象序列化为服务器端的byteBuffer(在示例中用字节数组说明)。 2:通过插座发送物体的soze 3:发送对象
在客户端,我首先在4字节的ByteBuffer中读取对象大小。第二步,我创建一个带有readed大小的新ByteBuffer,然后将数据从socketchannel读入Buffer。
如果你看一下代码,你可以看到(在客户端类中),我的期望是,socketChannel.read方法将返回与之前的readed对象大小相同的字节数。
但是在增加sendet字节数组之后,会出现很多错配和零大小。为什么会这样? socketchannel是非阻塞的。所以它应该能够读取配置的字节缓冲区中的所有内容。字节缓冲区的大小足够大。那么为什么有时会丢失字节?
非常感谢! 以下是示例代码:
主要类
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 :(得分:0)
您认为剩余数据在任何时候始终为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");
请记住,将套接字配置为非阻止模式并不能确保在检索到所有数据之前它不会返回
如果这仍然不适合您,请随意发表评论!