Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/344.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用Java NIO发送数据时出现延迟_Java_Sockets_Nio_Sfml - Fatal编程技术网

使用Java NIO发送数据时出现延迟

使用Java NIO发送数据时出现延迟,java,sockets,nio,sfml,Java,Sockets,Nio,Sfml,我需要你对JavaNIO包的建议。我在通过网络发送数据包时遇到延迟问题。原来的代码实际上是我的,但这里我将只向您展示一个最小的工作示例,其中问题被重现。虽然这段代码确实包含了来自SFML库的一些片段(实际上创建了一个窗口和一个事件循环),但我相信这对这个问题没有影响 这里我只展示部分代码,完整版本可用 因此,程序有两个实体:服务器和客户端。如果以服务器模式启动应用程序,则会创建服务器,开始侦听新连接,并自动创建新客户端并尝试连接到服务器。在客户端模式下,仅创建客户端并连接到服务器 该应用程序还创

我需要你对JavaNIO包的建议。我在通过网络发送数据包时遇到延迟问题。原来的代码实际上是我的,但这里我将只向您展示一个最小的工作示例,其中问题被重现。虽然这段代码确实包含了来自SFML库的一些片段(实际上创建了一个窗口和一个事件循环),但我相信这对这个问题没有影响

这里我只展示部分代码,完整版本可用

因此,程序有两个实体:服务器和客户端。如果以服务器模式启动应用程序,则会创建服务器,开始侦听新连接,并自动创建新客户端并尝试连接到服务器。在客户端模式下,仅创建客户端并连接到服务器

该应用程序还创建了一个新的基本GUI窗口,并启动了一个事件循环,所有事情都在该循环中发生

客户端向服务器发送数据包。它通过记录接受的事实来处理它们。客户端可以发送两种类型的数据包:定期数据包(具有增量ID)和事件数据包(应用程序对按下空格或M按钮作出反应)

客户端发送数据包:

public void update(Time dt) throws IOException {
    if (!isConnected) return;

    if (tickClock.getElapsedTime().compareTo(Time.getSeconds(1.f / 20.f)) > 0) {
        Packet intervalUpdatePacket = new Packet();
        intervalUpdatePacket.append(PacketType.INTERVAL_UPDATE);
        intervalUpdatePacket.append(intervalCounter++);

        PacketReaderWriter.send(socketChannel, intervalUpdatePacket);

        tickClock.restart();
    }
}

public void handleEvent(Event event) throws IOException {
    if (isConnected && (event.type == Event.Type.KEY_PRESSED)) {
        KeyEvent keyEvent = event.asKeyEvent();

        if (keyEvent.key == Keyboard.Key.SPACE) {
            LOGGER.info("press SPACE");
            Packet spacePacket = new Packet();
            spacePacket.append(PacketType.SPACE_BUTTON);
            PacketReaderWriter.send(socketChannel, spacePacket);
        }

        if (keyEvent.key == Keyboard.Key.M) {
            LOGGER.info("press M");
            Packet mPacket = new Packet();
            mPacket.append(PacketType.M_BUTTON);
            PacketReaderWriter.send(socketChannel, mPacket);
        }
    }
}
private void handleIncomingPackets() throws IOException {
    readSelector.selectNow();

    Set<SelectionKey> readKeys = readSelector.selectedKeys();
    Iterator<SelectionKey> it = readKeys.iterator();

    while (it.hasNext()) {
        SelectionKey key = it.next();
        it.remove();

        SocketChannel channel = (SocketChannel) key.channel();

        Packet packet = null;
        try {
            packet = PacketReaderWriter.receive(channel);
        } catch (NothingToReadException e) {
            e.printStackTrace();
        }

        if (packet != null) {
            // Interpret packet and react to it
            handleIncomingPacket(packet, channel);
        }
    }
}

private void handleIncomingPacket(Packet packet, SocketChannel channel) {
    PacketType packetType = (PacketType) packet.get();

    switch (packetType) {
        case INTERVAL_UPDATE:
            int intervalId = (int) packet.get();
            break;
        case SPACE_BUTTON:
            LOGGER.info("handling SPACE button");
            break;
        case M_BUTTON:
            LOGGER.info("handling M button");
            break;
    }
}
服务器接受数据包:

public void update(Time dt) throws IOException {
    if (!isConnected) return;

    if (tickClock.getElapsedTime().compareTo(Time.getSeconds(1.f / 20.f)) > 0) {
        Packet intervalUpdatePacket = new Packet();
        intervalUpdatePacket.append(PacketType.INTERVAL_UPDATE);
        intervalUpdatePacket.append(intervalCounter++);

        PacketReaderWriter.send(socketChannel, intervalUpdatePacket);

        tickClock.restart();
    }
}

public void handleEvent(Event event) throws IOException {
    if (isConnected && (event.type == Event.Type.KEY_PRESSED)) {
        KeyEvent keyEvent = event.asKeyEvent();

        if (keyEvent.key == Keyboard.Key.SPACE) {
            LOGGER.info("press SPACE");
            Packet spacePacket = new Packet();
            spacePacket.append(PacketType.SPACE_BUTTON);
            PacketReaderWriter.send(socketChannel, spacePacket);
        }

        if (keyEvent.key == Keyboard.Key.M) {
            LOGGER.info("press M");
            Packet mPacket = new Packet();
            mPacket.append(PacketType.M_BUTTON);
            PacketReaderWriter.send(socketChannel, mPacket);
        }
    }
}
private void handleIncomingPackets() throws IOException {
    readSelector.selectNow();

    Set<SelectionKey> readKeys = readSelector.selectedKeys();
    Iterator<SelectionKey> it = readKeys.iterator();

    while (it.hasNext()) {
        SelectionKey key = it.next();
        it.remove();

        SocketChannel channel = (SocketChannel) key.channel();

        Packet packet = null;
        try {
            packet = PacketReaderWriter.receive(channel);
        } catch (NothingToReadException e) {
            e.printStackTrace();
        }

        if (packet != null) {
            // Interpret packet and react to it
            handleIncomingPacket(packet, channel);
        }
    }
}

private void handleIncomingPacket(Packet packet, SocketChannel channel) {
    PacketType packetType = (PacketType) packet.get();

    switch (packetType) {
        case INTERVAL_UPDATE:
            int intervalId = (int) packet.get();
            break;
        case SPACE_BUTTON:
            LOGGER.info("handling SPACE button");
            break;
        case M_BUTTON:
            LOGGER.info("handling M button");
            break;
    }
}
问题是:在按下按钮(并从客户端发送相应的数据包)和在服务器上接受该数据包之间,我有相当大的延迟。如果以客户机模式启动应用程序的新实例(简而言之,只需添加一个新客户机),延迟会变得更大

我不明白为什么这些周期性的数据包会产生如此多的网络负载,以至于其他数据包无法通过,但也许我只是错过了一些东西。在这里,我不得不说我不是Java专家,所以不要因为我没有看到明显的东西而责备我:)

有人有什么想法吗


谢谢

我决定看看Github回购协议

您的Server.run()如下所示

    public void run() {
    while (isRunning) {
        try {
            handleIncomingConnections();
            handleIncomingPackets();
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            // Sleep to prevent server from consuming 100% CPU
            sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
睡眠(100)将导致每秒大约10次调用handleIncomingPackets()。handleIncomingPackets()将依次选择一个客户端通道,并对单个接收到的数据包调用handleIncomingPacket()。如果我理解正确,服务器将能够每秒处理每个客户端10个数据包

另一方面,客户端尝试每秒发送20个PacketType.INTERVAL\u UPDATE类型的数据包。客户端每秒必须发送更少的数据包,或者服务器每秒需要能够处理更多的数据包

当前的睡眠(100)意味着在服务器能够响应单个数据包之前,即使在非过载的情况下,也将始终有大约100毫秒的延迟。不过,如果您确保确实读取了通道上的所有可用数据包,而不是每次只读取一个数据包,那么这可能很好

总而言之:为了提高响应时间,你必须做的最小改变就是减少睡眠时间。10毫秒就可以了。但我也建议尝试检查每个迭代中是否有多个包可用

<snip>
while (peer->socket.receive(packet) == sf::Socket::Done)
        {
            // Interpret packet and react to it
            handleIncomingPacket(packet, *peer, detectedTimeout);
</snip>
更新: 在C++文件中,链接到我的直觉是每次迭代都读取一个以上的包。
<snip>
while (peer->socket.receive(packet) == sf::Socket::Done)
        {
            // Interpret packet and react to it
            handleIncomingPacket(packet, *peer, detectedTimeout);
</snip>
您需要确保在Java版本中也读取了所有可用的数据包


如果您只是想让自己相信客户端代码发送的数据包比服务器代码能够处理的数据包多,那么可以通过将sleep()临时设置为10 ms来快速完成。

定义“相当大的延迟”,并说明您认为这会造成“如此多的网络负载”的原因。我想说你在这里创建了太多的对象,尤其是太多的
ByteBuffers
。在频道的生命周期中,尝试使用每个频道一个,可能两个,一个用于阅读,一个用于写入。当我按“空格”时,大约2/3秒后,我会看到一条关于在服务器端接受包的消息。我会尽量减少缓冲区对象。我们能看到
PacketReaderWriter
吗?这是我问题中的最后一段代码。因为没有工作代码(不设置一个小测试)来重现您的问题。这里有一个猜测:This
intpacketsize=packetsizeradbuffer.getInt()bytesRead=channel.read(packetsizeradbuffer)时,code>可能会出现问题你读的少于四字节。谢谢你的回答,但是我不确定这是问题所在,因为我的代码只是一个简单的C++原代码端口,你可以找到。它的工作原理是完美的:在扫描C++文件后更新的答案。谢谢,我会检查的。