java - 将多个 android 设备连接到 "main"pc 应用程序

标签 java android

我想在计算机中创建和运行一个应用程序(在 Java 中),并允许多个用户使用他们的 Android 设备作为该主应用程序的输入设备。它必须对每个设备都是实时的。

例如:在训练课后做一些跟进练习。用户会自行注册(一种将字符串发送到 PC 上的主应用程序的简单表格),然后他们会收到一些问题,每个问题都会作为一个计时器,所以谁回答正确且速度更快,就会获得更好的成绩。

完成这项工作的最佳方法是什么?是的,如果这样更容易,连接可以通过互联网/局域网。

最佳答案

看起来这有两个部分。第一个是处理用户注册等的数据库系统...查看 SQL。有很多方法。就将多部手机连接到一台电脑而言,您需要一个可以处理线程的服务器和一个手机客户端。

服务器需要服务器套接字。服务器套接字一次可以接受多个连接的客户端。线程服务器可能如下所示:

public class ServerThread extends Thread
{
    //is the thread running
    private boolean running = true;

    //ports for the server sockets
    private final int dataPort;
    private final int filePort;

    private final String certificateDir;
    private final char[] password;

    private Vector<ClientHandlerThread> connectedClients = new Vector<ClientHandlerThread>(20, 5);
    private Properties userProperties = new Properties();

    public ServerThread(int dataPort,
                        int filePort,
                        String certificateDir,
                        char[] password,
                        Properties userProperties)
    {
        this.dataPort = dataPort;
        this.filePort = filePort;
        this.certificateDir = certificateDir;
        this.password = password;
        this.userProperties = userProperties;
    }

    public void run()
    {
        /*
         * We need a server socket that can accept traffic. I use one for file traffic and one
         * for data traffic although one socket could be used.
         */
        SSLServerSocket sslDataTraffic = null;
        SSLServerSocket sslFileTraffic = null;
        SSLServerSocketFactory sslFac = null;

        /*
         * Everything in the following block is related to creating a SSL security manager. 
         * If you don't need validated communications you don't have to use SSL. Just normal
         * sockets.
         */
        try
        {
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(new FileInputStream(certificateDir), password);

            TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            tmf.init(keyStore);

            KeyManagerFactory kmf = KeyManagerFactory.getInstance((KeyManagerFactory.getDefaultAlgorithm()));
            kmf.init(keyStore, password);

            System.setProperty("https.protocols", "SSL");
            SSLContext ctx = SSLContext.getInstance("SSL");
            ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
            sslFac = ctx.getServerSocketFactory();
        }
        catch(Exception e)
        {
            System.out.println("FAILED.");
            e.printStackTrace();
            System.exit(-1);
        }

        try
        {
            //create data server socket 
            System.out.print("Creating data socket......... ");
            sslDataTraffic = (SSLServerSocket) sslFac.createServerSocket(dataPort);
            System.out.println("DONE. Est. on:" + dataPort);

            //create file server socket
            System.out.print("Creating file socket......... ");
            sslFileTraffic = (SSLServerSocket) sslFac.createServerSocket(filePort);
            System.out.println("DONE. Est. on:" + filePort);
        }
        catch (IOException e)
        {
            System.out.println("FAILED.");
            System.out.println(e.toString() + " ::: " + e.getCause());
            System.exit(-1);
        }

        /*
         * This block is used to print the ip the server is running on. Easy to incorporate this here
         * so the information doesn't have to be gathered form another source.
         */
        try
        {
            System.out.print("Finishing.................... ");
            Socket s = new Socket("google.com", 80);
            System.out.println("DONE.");
            System.out.println("Server online at: " + s.getLocalAddress().getHostAddress());
            System.out.println("====================*====================");
            s.close();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }

        /*
         * This is the block that accepts connections from clients.
         */
        try
        {
            while (running)
            {
                //wait here until a connection is bound to new sockets through the server sockets
                SSLSocket sslDataTrafficSocketInstance = (SSLSocket) sslDataTraffic.accept();
                SSLSocket sslFileTrafficSocketInstance = (SSLSocket) sslFileTraffic.accept();
                //sockets to communicate with the client are created. Lets put them in a thread so 
                //we can continue to accept new clients while we work with the newly and previously
                //connected clients

                //create a new thread
                ClientHandlerThread c = new ClientHandlerThread(
                        sslDataTrafficSocketInstance, 
                        sslFileTrafficSocketInstance, 
                        userProperties);
                //start thread
                c.start();
                //add newly connected client to the list of connected clients
                connectedClients.add(c);
            }
        }
        catch (IOException e)
        {
            System.out.println("Fatal server error, terminating server and client handler threads");

            stopServer();
        }
    }
}

ClientHandlerThread 类的构造函数如下所示:

    private PrintWriter writer;
    private BufferedReader reader;
    private InputStream inputStream;
    private OutputStream outputStream;

    public ClientHandlerThread(
            SSLSocket dataSocket,
            SSLSocket fileSocket,
            Properties userProperties)
    {
        this.dataSocket = dataSocket;
        this.fileSocket = fileSocket;

        this.userProperties = userProperties;

        try
        {
            this.reader = new BufferedReader(new InputStreamReader(this.dataSocket.getInputStream()));
            this.writer = new PrintWriter(this.dataSocket.getOutputStream());
            this.inputStream = fileSocket.getInputStream();
            this.outputStream = fileSocket.getOutputStream();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }

通知流是从套接字创建的。这就是打开与客户的沟通 channel 。该线程可以发送一个接收数据和请求。您写什么请求以及处理它们的方式由您决定。

客户端看起来与服务器非常相似,但有一个很大的不同。客户端需要初始化握手。一方必须首先发送数据以初始化通信。由于客户端连接到服务器,我通常让客户端发送第一组数据。客户端的连接代码可能类似于此方法:

    private void connect()
    {
        try
        {
            SSLSocketFactory sslFac;
            SSLSocket dataSocket = null;
            SSLSocket fileSocket = null;

            /*
             * This block is nearly identical to the security block for the server side.  
             */
            try
            {
                KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
                keyStore.load(new FileInputStream(certificateDir), password.toCharArray());

                TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
                tmf.init(keyStore);

                KeyManagerFactory kmf = KeyManagerFactory.getInstance((KeyManagerFactory.getDefaultAlgorithm()));
                kmf.init(keyStore, password.toCharArray());

                System.setProperty("https.protocols", "SSL");
                SSLContext ctx = SSLContext.getInstance("SSL");
                ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
                sslFac = ctx.getSocketFactory();

                String ip = "<THE SERVER'S IP ADDRESS>";
                dataSocket = (SSLSocket) sslFac.createSocket(ip, dataPort);
                fileSocket = (SSLSocket) sslFac.createSocket(ip, filePort);
            }
            catch(Exception e)
            {
                System.out.println("FAILED.");
                e.printStackTrace();
                System.exit(-1);
            }

            reader = new BufferedReader(new InputStreamReader(dataSocket.getInputStream()));
            writer = new PrintWriter(dataSocket.getOutputStream());
            OutputStream fileOut = fileSocket.getOutputStream();

            writer.println("CLIENT_HANDSHAKE_INIT");
            writer.flush();
            }
     }

此时你应该有一个客户端连接到服务器并且客户端应该已经初始化了握手。您的流在两端相互开放,允许服务器和客户端进行通信。在这一点上,您可以开始完善和构建服务器和客户端来执行您真正想要执行的操作。我提供的代码缺少露水部分,您在根据您的特定需求定制系统时需要填写这些部分。我提供了这个系统作为示例供您遵循。 一些注意事项。请记住,必须有人开始握手才能进行通信。请记住,必须刷新流才能传输数据。此安全模型不适用于公共(public)连接。我严格地试图阻止外部连接成功。如果您需要安全连接,则需要对 SSL 进行更多研究。

希望这能让您对服务器-客户端模型以及您想用它做什么有所了解。

干杯,

关于java - 将多个 android 设备连接到 "main"pc 应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22973045/

相关文章:

c# - MVVX无法从MvxDefaultViewModelLocator初始化ViewModel

Android TextView 响应 html <a> 点击

java - 表单验证后的消息

java - 我如何在 Linux 中选择正确的 Activity 串口?

java - 将 CookieStore 转换为字符串 : pb with encode/decode value

java - 在Android中获取间隔日期?

android - 在 Android 上呈现 Kannada(印度语)文本

JavaFX:如何知道应用程序正在哪个系统上运行?

java - 从搜索结果中删除 ""

java - Android Studio编译器错误: cannot find a method listed in android studio tutorial