为什么我应该使用NIO进行TCP多人游戏而不是简单的套接字(IO) - 或者:块在哪里?

时间:2012-01-05 13:50:33

标签: java android sockets nio multiplayer

我正在尝试为Android设备创建一个简单的多人游戏。我一直在考虑网络代码,现在阅读很多关于套接字的网页。 Android应用程序只是一个客户端,只能连接到一个服务器。

几乎所有地方(在这里)都会得到建议使用NIO或使用NIO的框架,因为“阻塞”。 我试图了解简单套接字实现的问题,所以我创建了一个简单的测试来试用它:

我的主要申请:

[...]
Socket clientSocket = new Socket( "127.0.0.1", 2593 );
new Thread(new PacketReader(clientSocket)).start();
PrintStream os = new PrintStream( clientSocket.getOutputStream() );
os.println( "kakapipipopo" );
[...]

PacketReader线程:

class PacketReader implements Runnable
{
    Socket m_Socket;
    BufferedReader m_Reader;

    PacketReader(Socket socket)
    {
        m_Reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    }

    public void run()
    {
        char[] buffer = new char[200];
        int count = 0;
        while(true)
        {
            count = m_Reader.read(buffer, 0, 200);
            String message = new String(buffer, 0, count);
            Gdx.app.log("keks", nachricht);
        }
    }
}

我无法遇到我应该得到的阻塞问题。我认为read()函数会阻止我的应用程序,我什么也做不了 - 但一切都运行得很好。 我一直在想:如果我只是在我的应用程序中创建一个输入和输出缓冲区并创建两个线程来从我的两个缓冲区写入和读取套接字怎么办?这会有用吗? 如果是的话 - 为什么每个人都推荐NIO?在正常IO方式的某个地方必须发生阻塞,但我找不到它。 是否有任何其他好处使用NIO进行Android多人游戏?我认为NIO似乎更复杂,因此可能不太适合移动设备,但对于移动设备而言,简单的套接字方式可能更糟。

如果有人能告诉我问题发生在哪里,我会很高兴。我并不害怕NIO,但至少我想知道我为什么要使用它:D

问候

-Thomas

2 个答案:

答案 0 :(得分:-1)

阻塞是,read()将阻塞当前线程,直到它可以从socket的输入流中读取数据。因此,您需要一个专用于该单个TCP连接的线程。

如果您的服务器连接的客户端设备超过10k,该怎么办?您需要至少10k个线程来处理所有客户端设备(假设每个设备保持单个TCP连接),无论它们是否处于活动状态。您在上下文切换和其他多线程开销上有太多开销,即使其中只有100个处于活动状态。

NIO使用选择器模型来处理这些客户端,这意味着您不需要为每个TCP连接提供专用线程来接收数据。您只需选择所有活动连接(已收到数据)并处理这些活动连接。您可以控制服务器端应维护的线程数。

答案 1 :(得分:-1)

修改 这个答案有点不能完全回答OP的要求。对于客户端来说很好,因为客户端将只连接到一个服务器。虽然我的回答提供了关于阻止和非阻塞IO的一般概念。

我知道这个答案将在3年后出现,但这可能会对将来有所帮助。

在阻塞套接字模型中,如果数据不可用于读取或服务器尚未准备好写入,则网络线程将等待请求读取或写入套接字,直到它获取或发送数据为止要么 超时换句话说,如果程序无法继续,程序可能会在此时暂停一段时间。要取消此操作,我们可以为每个连接创建一个线程,该线程可以同时处理来自每个客户端的请求。如果选择这种方法,应用程序的可伸缩性可能会受到影响,因为在连接数千个客户端的情况下,由于线程的创建成本很高并且可能影响系统的性能,因此有数千个线程会占用系统的所有内存。应用

在非阻塞套接字模型中,在套接字上读取或写入的请求会立即返回它是否成功,换句话说,是异步的。这使网络线程保持忙碌状态。然后我们的任务是决定是再次尝试还是考虑完成读/写操作。这样就创建了一种事件驱动的通信方法,我们可以在需要时创建线程,从而实现更具伸缩性的系统。

下图解释了阻塞和非阻塞套接字模型之间的区别。 enter image description here