在 java (IRC) 中避免速率限制(节流)

Avoiding rate-limiting (throttling) in java (IRC)

所以我一直在写一个基于 java 的 irc-bot,它相当简单。与服务器建立套接字连接,将缓冲的读取器/写入器附加到套接字,然后使用这些缓冲区进行读取/写入。

我没有 运行 遇到过问题,除了当我打印出一个 json 对象并因过度泛滥而被踢出网络时。我不确定网络的消息速率限制,但我确实通过相同的简单函数传递我的所有消息。

我希望为其添加某种 x 字节/时间范围限制。有人建议我研究一下 NIO,但这似乎有点过度设计了这个问题。

这是我当前的写入 irc 通道的方法:

public static void writeMsg(BufferedWriter writer, String Channel, String Message) {
    try {
        System.out.println("Bot Command: PRIVMSG " + Channel + Message); //diagnostic
        writer.write("PRIVMSG " + Channel + Message);
        writer.flush();
    } catch(IOException ioe) {
        ioe.printStackTrace();
    }
}

可能传入/传出该函数的示例:

输入:

writer (my BufferedWriter object), "#Testing1234: ", "!wiki China";

输出:

PRIVMSG #BeginnersProgramming :http://en.wikipedia.org/wiki/China

我会在你的方法开始时随机休眠。这样,您就可以模拟人类打字。

非线程安全版本

private static SecureRandom sr = SecureRandom.getInstance("SHA1PRNG", "SUN"); 

public static void writeMsg(BufferedWriter writer, String Channel, String Message){
    try {
        // Sleep randomly between 2 (inclusive) and 5 (exclusive) seconds.
        int duration = 2000 + sr.nextInt(3000);
        System.out.println("Pausing execution for " + duration + " ms..."); 
        TimeUnit.MILLISECONDS.sleep(duration);

        System.out.println("Bot Command: PRIVMSG " + Channel + Message); //diagnostic
        writer.write("PRIVMSG " + Channel + Message);
        writer.flush();
    } catch(IOException ioe){
       ioe.printStackTrace();
    } catch (InterruptedException e) {
       e.printStackTrace();
    }
}

线程安全版本

如果您的方法将被多个线程调用,请考虑此代码使用锁。锁在发送消息时增加了一些随机性。

private static final Lock writeLock = new ReentrantLock();
private static SecureRandom sr = SecureRandom.getInstance("SHA1PRNG", "SUN"); 

public static void writeMsg(BufferedWriter writer, String Channel, String Message){
    writeLock.lock();
    try {
        // Sleep randomly between 2 (inclusive) and 5 (exclusive) seconds.
        int duration = 2000 + sr.nextInt(3000);
        System.out.println("Pausing execution for " + duration + " ms..."); 
        TimeUnit.MILLISECONDS.sleep(duration);

        System.out.println("Bot Command: PRIVMSG " + Channel + Message); //diagnostic
        writer.write("PRIVMSG " + Channel + Message);
        writer.flush();
    } catch(IOException ioe){
       ioe.printStackTrace();
    } catch (InterruptedException e) {
       e.printStackTrace();
    } finally {
       writeLock.unlock();
    }
}

I'm hoping to add some kind of x bytes / timeframe limit to it

最简单的方法是

final int rateLimit = 50; // Bytes per second

final float msPerByte = 1000.0f / rateLimit;

writer.write(message);

int numBytes = message.length();

Thread.sleep((int)(msPerByte * numBytes + 1));

但是,根据消息的长度,一条消息的单次突发可能已经触发了服务器的速率限制。在这种情况下,您必须将消息拆分为更小的部分,并在适当的延迟之间一个接一个地发送。

如果仅在每个时间段的消息基础上实施速率限制,您需要做的就是sleep()每条消息后的固定时间。

我相信有更复杂的算法在起作用,其中可能包括更多基于时间的参数来决定。