【问题标题】:Java Handling Multiple Client SocketsJava 处理多个客户端套接字
【发布时间】:2013-12-28 22:50:31
【问题描述】:

处理与同一服务器/IP 的多个客户端连接的有效方法是什么。

目前我有一个服务器套接字,每次新玩家加入游戏时都会创建一个新线程。

我如何处理玩家?我在想我可以通过 IP 地址来做到这一点,但我不知道该怎么做。此外,由于我正在测试本地连接以及玩家如何在同一个 IP 上使用多个帐户,这种方法似乎效率不高。

我希望能够管理玩家,让他们能够将他们踢出游戏并修改他们的帐户。提前致谢。 :)

【问题讨论】:

  • 定义'处理玩家','管理玩家',...
  • “处理多个客户端连接到同一个服务器/IP”。我希望能够关闭来自服务器的套接字连接。对于我想要的任何连接。
  • 你的问题的答案很大程度上取决于这是什么类型的游戏。来自每个客户的输入是否需要在每个滴答声中提取、处理和发送?您使用的是 udp 还是 tcp 套接字?通信是稳定的还是突发的?
  • 需要拉取处理是的。仅在需要时发送。呃,它只是一个Java Socket。我假设它是TCP。我在想,由于端口取决于套接字连接而不是 IP 位置,因此它可能是处理它们的好方法。
  • 关闭一个套接字就是 Socket.close()。我仍然没有看到问题。

标签: java sockets client


【解决方案1】:

这就是我建立网络的方式(如果您愿意,请随时发表评论):

“主”服务器包含 ServerSocket。 “子”服务器处理各个客户端。作为一个类比,考虑一家餐馆。 “主服务器”是接待员。当客户进来时,他接受客户的请求并将其分配给“子服务器”。 “子服务器”是服务员。他们处理单个客户请求。因此,你会有这样的事情:

public class Server extends Thread {

    final private ServerSocket m_serverSocket;
    final public static int MAX_CLIENTS = 3000;
    final private SubServer[] m_clientConnections = new SubServer[ MAX_CLIENTS ];

    public Server( int port ) throws IOException {
         this.m_serverSocket = new ServerSocket( port );
         start();
    }

    @Override
    public void run() {
        while ( !this.interrupted() ) {
             //wait for clients
             Socket connection = this.m_serverSocket.accept();
             assignConnectionToSubServer( connection );
        }
    }

    public void assignConnectionToSubServer( Socket connection ) {
         for ( int i = 0 ; i < MAX_CLIENTS ; i++ ) {

             //find an unassigned subserver (waiter)
             if ( this.m_clientConnections[ i ] == null ) {
                  this.m_clientConnections[ i ] = new SubServer( connection , i );
                  break;
             }
         }
    }

    protected class SubServer extends Thread {

        final private int m_id;
        final private Socket m_connection;

        //you can store additional client properties here if you want, for example:
        private int m_gameRating = 1500;

        public SubServer( Socket connection , int id ) {
            this.m_id = id;
            this.m_connection = connection;
            start();
        }

        @Override
        public void run() {
             while( !this.interrupted() ) {
                 //process a client request
                 //this is for you to implement
             }
        }

        //as an example, if you read String messages from your client,
        //just call this method from the run() method to process the client request
        public void process( String message ) {

        }

        /**
         * terminates the connection with this client (i.e. stops serving him)
         */
        public void close() {
            try {
                 this.m_connection.close();
            } catch ( IOException e ) {
                 //ignore
            }
        }
    }
}

因此,有了这一切,您应该能够为许多客户提供服务。如果你想踢客户,就这样做

clientConnection[ i ].close();

每个客户端的 id 都存储在 SubServer 对象中。

如果需要,您可以在每个子服务器中存储其他属性。一旦建立了网络,这就像一个未联网的程序一样“正常”。

编辑:

现在直接回答你的问题:

问。我如何处理球员?

A.您使用 SubServer 对象处理玩家。您可以在 SubServer 类中定义其他方法来实现您想要的功能。具体来说,如果您需要区分用户,请强制他们提供唯一的用户名,然后才能开始玩游戏。

问。我希望能够管理玩家,让他们能够退出游戏并修改他们的帐户

A.使用 close() 方法启动,它们将与服务器断开连接。您可以在 SubServer 对象中指定帐户属性,并在服务器运行时修改这些属性。

编辑:

所以现在,你可能有一个 ActionListener 来观察你的 JList 和所有用户

public class UserListListener implements ActionListener {

    final private Server m_networking;

    //you need to pass a reference to the server to your listener
    //you may also need to pass a reference to the user interface (JList) to your listener as well
    public UserListListener( Server networking ) {
        this.m_networking = networking;
    }

    public String getSelectedUser() {
        //determine the selected user on the JList
    }

    @Override
    public void actionPerformed( ActionEvent e ) {
        String command = e.getActionCommand();
        if ( command.equals( "kick" ) ) {

            //so here, you determine the user that was selected and tell the server to kick him
            server.kick( getSelectedUser() );
        }
    }
}

编辑:

在服务器类中

public void kick( String username ) {
    for( int i = 0 ; i < MAX_CLIENTS ; i++ ) {
        if ( this.m_clients[ i ].getUsername().equals( username ) {
            this.m_clients[ i ].close();
            this.m_clients[ i ] = null;
        }
    }
}

【讨论】:

  • 看起来这可能工作得很好。我会试试这个:) 谢谢。
  • 效果很好!但是,我有一个问题。我试图通过我的服务器控制面板踢用户。在我的控制面板中,我有一个 JList,我可以在其中选择我当前登录的任何用户。 (当玩家登录时,我从客户端获取用户名)。如何使用您的 Server 类通过 kick 命令踢玩家?这是我使用您的课程更新的代码。 pastebin.com/ZS7SM1XB 顺便说一句,我的 ControlPanel 类正在将 String 用户作为 JList 中的选定用户发送。感谢您的帮助。
  • 我假设您的控制面板有某种监听器(例如 ActionListener)?我的方法是将 Server 对象传递给 ActionListener 构造函数。然后,在ActionListener 中就会有一个对Server 的引用。在 ActionListener 中,当您单击“kick”时,您将在 ActionListener 中获得一个事件并执行 actionPerformed() 方法。从 actionPerformed() 方法中,您可以调用 server.kick(),因为您的 ActionListener 现在具有对服务器的引用。 (见上面的编辑)
  • 另外,如果您觉得这回答了您的问题,您介意通过单击我的答案左上角的复选标记来接受它吗?谢谢,很高兴我能帮上忙!
  • 我一定会接受的。但是,我还有几个问题。当 getSelectedUser 基于字符串时,如何使用您的命令踢用户? JList 如何知道哪个用户线程连接到列表中的哪个用户名?...某种 IP 抓取器可能是必要的?
猜你喜欢
  • 1970-01-01
  • 2017-09-10
  • 1970-01-01
  • 2016-01-05
  • 1970-01-01
  • 1970-01-01
  • 2015-06-25
  • 1970-01-01
  • 2017-02-25
相关资源
最近更新 更多