首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >SocketChannel:读取的字节不够

SocketChannel:读取的字节不够
EN

Stack Overflow用户
提问于 2018-03-13 19:55:54
回答 1查看 1.5K关注 0票数 1

我正在通过socketChannel实现客户端服务器通信。在使用较大的objets进行负载测试期间,我在客户端遇到了问题。因此,我已经实现了一个测试程序来验证我的问题,并在这里加以说明。

首先,一个小的解释:我不知道客户端将通过套接字发送的对象的大小。因此,我将我的发送分为两部分: 1.:将对象序列化为服务器端的byteBuffer (在用字节数组演示的示例中)。2.:通过套接字3.:发送对象的soze

在客户端,我首先以4字节的ByteBuffer读取对象大小.作为第二步,我创建一个具有读取大小的新ByteBuffer,然后将数据从套接字通道读取到缓冲区中。

如果您看一下代码(在客户端类中),我的期望是,socketChannel.read方法将返回与前面读取的对象大小相同的字节计数。

但是在增加了sendet字节数组后,会出现大量的不匹配和零大小。为什么会发生这种事??套接字通道是非阻塞的。因此,它应该能够读取配置的字节缓冲区中的所有内容。字节缓冲区的大小足够大。那么,为什么有时会缺少字节呢?

非常感谢!下面是示例代码:

主类

代码语言:javascript
复制
package socketChannelMaxTest;

import java.io.IOException;

public class MaxTest {

    public static void main(String[] args) throws IOException {
        Sender.startServer();
        new Client();
    }

}

服务器发送者

代码语言:javascript
复制
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();
    }
}

客户端接收器

代码语言:javascript
复制
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();
    }

}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-03-13 21:03:08

假设您的剩余数据在任何时候总是为0,这是有问题的。

代码语言:javascript
复制
// should be 0
int remainginBytes = dataBuffer.remaining();

你不能确定这种情况在任何时候都会发生。如果数据太大,则需要从SocketChannel再读取一次,以检索其余信息。

您应该有一个从socketChannel读取的循环,直到没有剩余的字节为止。

代码语言:javascript
复制
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");

记住,将套接字配置为非阻塞模式并不能确保在检索所有数据之前它不会返回

如果这仍然对你不起作用,请随时发表评论!

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49264833

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档