使 InputStream 成为非阻塞的

Make InputStream non-blocking

目前我有一个侦听连接的服务器(它是我拥有的手机游戏的基本高分服务器),每 1000 毫秒循环一次连接并侦听任何传入数据。

public void readData(Connection c) throws IOException {
    PacketBuffer readBuffer = new PacketBuffer(Server.PACKET_CAPACITY);
    int packetSize = c.getIn().read();
    c.getIn().mark(packetSize);
    byte[] buffer = new byte[packetSize];
    c.getIn().read(buffer, 0, buffer.length);
    readBuffer.setBuffer(buffer);
    packetHandler.addProcess(c, readBuffer);
}

我使用自己的 PacketBuffer,我需要找到一种方法,使 c.getIn().read()(即我的连接 InputStream)不会阻塞。目前,套接字设置为 500 毫秒超时,我的服务器会 运行 这样很好。我的问题是,如果有人试图让他们自己的程序连接以尝试破解他们自己的高分或 ddos​​ 服务器,它将变得与一堆无用的连接混淆,当连接不写入时,这些连接会阻塞线程 500 毫秒。

你不能。 InputStreams 正在阻塞。时期。很难看出非阻塞模式实际上如何解决您提到的问题。我建议重新设计。

你可以尝试这样的事情。每次调用 readData 时,它都会检查是否有字节可供读取。我在这里使用了 while 循环,因为您希望它在线程再次休眠之前处理它可以处理的所有数据。如果每 x 毫秒只读取一条消息,这将确保消息不会被备份。

public void readData(Connection c) throws IOException {
    while (c.getIn().available() > 0) {
        int packetSize = c.getIn().read();
        c.getIn().mark(packetSize);
        byte[] buffer = new byte[packetSize];
        c.getIn().read(buffer, 0, buffer.length);
        PacketBuffer readBuffer = new PacketBuffer(Server.PACKET_CAPACITY);
        readBuffer.setBuffer(buffer);
        packetHandler.addProcess(c, readBuffer);
    }

我不知道你为什么要使用标记方法。我觉得有问题。

您还确实需要使用 readFully() 样式的方法(请参阅 DataInputStream),它不会 return 直到它确实读取了完整的字节数组。常规读取始终可以 "return short",即使发送方已发送完整数据块(由于网络数据包大小等)。

在java中有两种经典的服务器实现方式。

第一种也是最古老的方法是为每个连接的客户端使用 read/write 线程对。这对于没有大量连接客户端的小型服务器来说是可以的,因为每个客户端都需要两个线程来管理它。它不能很好地扩展到很多并发客户端。

第二种更新的方法是使用 java.nio.ServerSocketChanneljava.nio.SocketChanneljava.nio.Selector。这三个 类 允许您在单个线程中管理您连接的每个客户端的所有 IO 操作。 Here 是如何使用 java.nio 包实现非常基本的服务器的示例。

实现服务器的更好方法是使用第三方框架。我过去使用过的一个很棒的库是 Netty。它处理套接字的所有细节,并提供一个相当干净和简单的 api,可以很好地扩展。