当前位置: 首页 > 知识库问答 >
问题:

Android TCP连接(多客户端)

申屠浩歌
2023-03-14

我使用这个(Android TCP连接增强的)教程来创建简单的JAVA TCPServer和Android TCPClient。它工作得很好,但使用这段代码我只能同时将一个设备连接到服务器。我必须更改什么才能连接多个设备?

public class Constants {

    public static final String CLOSED_CONNECTION = "kazy_closed_connection";
    public static final String LOGIN_NAME = "kazy_login_name";

}
public class MainScreen extends JFrame {

    /**
     * 
     */
    private static final long serialVersionUID = 8399514248326995812L;
    private JTextArea messagesArea;
    private JButton sendButton;
    private JTextField message;
    private JButton startServer;
    private JButton stopServer;
    private TcpServer mServer;

    public MainScreen() {

        super("MainScreen");

        JPanel panelFields = new JPanel();
        panelFields.setLayout(new BoxLayout(panelFields, BoxLayout.X_AXIS));

        JPanel panelFields2 = new JPanel();
        panelFields2.setLayout(new BoxLayout(panelFields2, BoxLayout.X_AXIS));

        // here we will have the text messages screen
        messagesArea = new JTextArea();
        messagesArea.setColumns(30);
        messagesArea.setRows(10);
        messagesArea.setEditable(false);

        sendButton = new JButton("Send");
        sendButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                // get the message from the text view
                String messageText = message.getText();
                // add message to the message area
                messagesArea.append("\n" + messageText);
                if (mServer != null) {
                    // send the message to the client
                    mServer.sendMessage(messageText);
                }
                // clear text
                message.setText("");
            }
        });

        startServer = new JButton("Start");
        startServer.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {

                // creates the object OnMessageReceived asked by the TCPServer
                // constructor
                mServer = new TcpServer(new TcpServer.OnMessageReceived() {
                    @Override
                    // this method declared in the interface from TCPServer
                    // class is implemented here
                    // this method is actually a callback method, because it
                    // will run every time when it will be called from
                    // TCPServer class (at while)
                    public void messageReceived(String message) {
                        messagesArea.append("\n " + message);
                    }
                });
                mServer.start();

                // disable the start button and enable the stop one
                startServer.setEnabled(false);
                stopServer.setEnabled(true);

            }
        });

        stopServer = new JButton("Stop");
        stopServer.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {

                if (mServer != null) {
                    mServer.close();
                }

                // disable the stop button and enable the start one
                startServer.setEnabled(true);
                stopServer.setEnabled(false);

            }
        });

        // the box where the user enters the text (EditText is called in
        // Android)
        message = new JTextField();
        message.setSize(200, 20);

        // add the buttons and the text fields to the panel
        panelFields.add(messagesArea);
        panelFields.add(startServer);
        panelFields.add(stopServer);

        panelFields2.add(message);
        panelFields2.add(sendButton);

        getContentPane().add(panelFields);
        getContentPane().add(panelFields2);

        getContentPane().setLayout(
                new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));

        setSize(300, 170);
        setVisible(true);
    }

}
public class TcpServer extends Thread {

    public static final int SERVERPORT = 4444;
    // while this is true the server will run
    private boolean running = false;
    // used to send messages
    private PrintWriter bufferSender;
    // callback used to notify new messages received
    private OnMessageReceived messageListener;
    private ServerSocket serverSocket;
    private Socket client;

    /**
     * Constructor of the class
     * 
     * @param messageListener
     *            listens for the messages
     */
    public TcpServer(OnMessageReceived messageListener) {
        this.messageListener = messageListener;
    }

    public static void main(String[] args) {

        // opens the window where the messages will be received and sent
        MainScreen frame = new MainScreen();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);

    }

    /**
     * Close the server
     */
    public void close() {

        running = false;

        if (bufferSender != null) {
            bufferSender.flush();
            bufferSender.close();
            bufferSender = null;
        }

        try {
            client.close();
            serverSocket.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println("S: Done.");
        serverSocket = null;
        client = null;

    }

    /**
     * Method to send the messages from server to client
     * 
     * @param message
     *            the message sent by the server
     */
    public void sendMessage(String message) {
        if (bufferSender != null && !bufferSender.checkError()) {
            bufferSender.println(message);
            bufferSender.flush();
        }
    }

    public boolean hasCommand(String message) {
        if (message != null) {
            if (message.contains(Constants.CLOSED_CONNECTION)) {
                messageListener.messageReceived(message.replaceAll(
                        Constants.CLOSED_CONNECTION, "")
                        + " disconnected");
                // close the server connection if we have this command and
                // rebuild a new one
                close();
                runServer();
                return true;
            } else if (message.contains(Constants.LOGIN_NAME)) {
                messageListener.messageReceived(message.replaceAll(
                        Constants.LOGIN_NAME, "") + " connected");
                return true;
            }
        }

        return false;
    }

    /**
     * Builds a new server connection
     */
    private void runServer() {
        running = true;

        try {
            System.out.println("S: Connecting...");

            // create a server socket. A server socket waits for requests to
            // come in over the network.
            serverSocket = new ServerSocket(SERVERPORT);

            // create client socket... the method accept() listens for a
            // connection to be made to this socket and accepts it.
            client = serverSocket.accept();

            System.out.println("S: Receiving...");

            try {

                // sends the message to the client
                bufferSender = new PrintWriter(new BufferedWriter(
                        new OutputStreamWriter(client.getOutputStream())), true);

                // read the message received from client
                BufferedReader in = new BufferedReader(new InputStreamReader(
                        client.getInputStream()));

                // in this while we wait to receive messages from client (it's
                // an infinite loop)
                // this while it's like a listener for messages
                while (running) {

                    String message = null;
                    try {
                        message = in.readLine();
                    } catch (IOException e) {
                        System.out.println("Error reading message: "
                                + e.getMessage());
                    }

                    if (hasCommand(message)) {
                        continue;
                    }

                    if (message != null && messageListener != null) {
                        // call the method messageReceived from ServerBoard
                        // class
                        messageListener.messageReceived(message);
                    }
                }

            } catch (Exception e) {
                System.out.println("S: Error");
                e.printStackTrace();
            }

        } catch (Exception e) {
            System.out.println("S: Error");
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        super.run();

        runServer();

    }

    // Declare the interface. The method messageReceived(String message) will
    // must be implemented in the ServerBoard
    // class at on startServer button click
    public interface OnMessageReceived {
        public void messageReceived(String message);
    }

}
public class TCPClient {

    public static final String SERVER_IP = "192.168.0.102"; // your computer IP
                                                            // address
    public static final int SERVER_PORT = 4444;
    // message to send to the server
    private String mServerMessage;
    // sends message received notifications
    private OnMessageReceived mMessageListener = null;
    // while this is true, the server will continue running
    private boolean mRun = false;
    // used to send messages
    private PrintWriter mBufferOut;
    // used to read messages from the server
    private BufferedReader mBufferIn;

    private String uid;

    /**
     * Constructor of the class. OnMessagedReceived listens for the messages
     * received from server
     */
    public TCPClient(OnMessageReceived listener) {
        mMessageListener = listener;
    }

    /**
     * Sends the message entered by client to the server
     * 
     * @param message
     *            text entered by client
     */
    public void sendMessage(String message) {
        if (mBufferOut != null && !mBufferOut.checkError()) {
            mBufferOut.println(message);
            mBufferOut.flush();
        }
    }

    /**
     * Close the connection and release the members
     */
    public void stopClient() {

        // send mesage that we are closing the connection
        TelephonyManager tManager = (TelephonyManager) MyApplication.getInstance().getSystemService(Context.TELEPHONY_SERVICE);
        uid = tManager.getDeviceId();
        sendMessage(Constants.CLOSED_CONNECTION + "id: " + uid);

        mRun = false;

        if (mBufferOut != null) {
            mBufferOut.flush();
            mBufferOut.close();
        }

        mMessageListener = null;
        mBufferIn = null;
        mBufferOut = null;
        mServerMessage = null;
    }

    public void run() {

        mRun = true;

        try {
            // here you must put your computer's IP address.
            InetAddress serverAddr = InetAddress.getByName(SERVER_IP);

            MyLog.e("TCP Client", "C: Connecting...");

            // create a socket to make the connection with the server
            Socket socket = new Socket(serverAddr, SERVER_PORT);

            try {

                // sends the message to the server
                mBufferOut = new PrintWriter(new BufferedWriter(
                        new OutputStreamWriter(socket.getOutputStream())), true);

                // receives the message which the server sends back
                mBufferIn = new BufferedReader(new InputStreamReader(
                        socket.getInputStream()));
                // send login name
                TelephonyManager tManager = (TelephonyManager) MyApplication.getInstance().getSystemService(Context.TELEPHONY_SERVICE);
                uid = tManager.getDeviceId();
                sendMessage(Constants.LOGIN_NAME + "id: " + uid);

                // in this while the client listens for the messages sent by the
                // server
                while (mRun) {

                    mServerMessage = mBufferIn.readLine();

                    if (mServerMessage != null && mMessageListener != null) {
                        // call the method messageReceived from MyActivity class
                        mMessageListener.messageReceived(mServerMessage);
                    }

                }

                MyLog.e("RESPONSE FROM SERVER", "S: Received Message: '"
                        + mServerMessage + "'");

            } catch (Exception e) {

                MyLog.e("TCP", "S: Error", e);

            } finally {
                // the socket must be closed. It is not possible to reconnect to
                // this socket
                // after it is closed, which means a new socket instance has to
                // be created.
                socket.close();
            }

        } catch (Exception e) {

            MyLog.e("TCP", "C: Error", e);

        }

    }

    // Declare the interface. The method messageReceived(String message) will
    // must be implemented in the MyActivity
    // class at on asynckTask doInBackground
    public interface OnMessageReceived {
        public void messageReceived(String message);
    }
}
public class Constants {

    public static final String CLOSED_CONNECTION = "kazy_closed_connection";
    public static final String LOGIN_NAME = "kazy_login_name";

}
@Override
protected void onPause() {
    super.onPause();
    if(connect != null) {
        connect.cancel(true);
    }
    if(mTcpClient != null) {
        MyLog.d(TAG, "stopClient");
        mTcpClient.stopClient();
        mTcpClient = null;
    }
}

public class ConnectTask extends AsyncTask<String,String,TCPClient> {

    @Override
    protected TCPClient doInBackground(String... message) {

        MyLog.d(TAG, "doInBackground");

        //we create a TCPClient object and
        mTcpClient = new TCPClient(new TCPClient.OnMessageReceived() {
            @Override
            //here the messageReceived method is implemented
            public void messageReceived(String message) {

                //this method calls the onProgressUpdate
                publishProgress(message);

            }
        });
        mTcpClient.run();

        return null;
    }

    @Override
    protected void onProgressUpdate(String... values) {
        super.onProgressUpdate(values);
        MyLog.d(TAG, "onProgressUpdate");
        View view = adapter.getChildView(0, 0, false, null, null);
        TextView text = (TextView) view.findViewById(R.id.betChildOdd);
        child2.get(0).get(0).put("OLD", text.getText().toString());
        child2.get(0).get(0).put(CONVERTED_ODDS, values[0].toString());
        child2.get(0).get(0).put("CHANGE", "TRUE");
        adapter.notifyDataSetChanged();
    }
}

共有1个答案

胡越
2023-03-14

我没有仔细阅读您的所有代码,但我想到的第一件事是:您是基于多线程服务器架构构建应用程序的吗?对于我在代码中看到的内容,我注意到您没有将socket.accept()之后的执行委托给另一个线程,这就是您不能同时回答多个客户机的原因。

请记住,您需要注意对相同数据结构的并发访问可能产生的竞争条件。

这是TCP服务器应该遵循的模式:http://tutorials.jenkov.com/java-multithreaded-servers/multithreaded-server.html

 类似资料:
  • 在Netty中创建客户端连接时,我有一个问题。 这里,为什么我们没有一个bind方法,将通道绑定到发起客户端连接的端口(在客户端)?我们唯一需要提供的就是给出服务器地址和端口如下: 这是在客户端还是服务器端创建了一个新的通道?此通道绑定在客户端的哪个端口? 我们在执行服务器端引导时进行绑定,如下所示 我很困惑,不明白客户端从哪个端口向服务器发送数据,使用的是什么通道?

  • 执行kafka客户端的生产者/消费者连接池有意义吗? kafka是否在内部维护已初始化并准备好使用的连接对象列表? 我们希望最小化连接创建的时间,这样在发送/接收消息时就不会有额外的开销。 目前,我们正在使用apache共享池库来保持连接。 任何帮助都将不胜感激。

  • 我正在尝试从另一台机器创建与基于java的套接字服务器的多个客户端连接。服务器和客户端都使用Netty 4进行NIO。在服务器端,我使用了boss和Worker group,它能够在单个linux盒上接收和服务器100000并发连接(在设置内核参数和ulimited之后)。 但是,我最终在客户端为每个连接创建了一个新线程,这导致了JVM线程限制异常。 有人能告诉我,我如何使用Netty从客户端创建

  • 我想知道以下问题的答案: 1)如果Ignite服务器重新启动,我需要重新启动客户端(web应用程序)。是否有任何方法可以在服务器重新启动时重新连接到服务器。我知道当服务器重新启动时,它分配了一个不同的ID,因此当前现有的连接变得过时。是否有方法克服这个问题,如果是的话,哪一个版本的Ignite支持这个功能。目前我使用1.7版本 3)如果我有一个大对象要缓存,我发现序列化和反序列化在Ignite中需

  • 问题内容: 我正在设计一个将Redis用作数据库的Web服务,并且我想了解使用Redis与StackService客户端连接的最佳实践。 关键是我一直在阅读有关Redis的文章,发现与服务器交互的最佳方法是使用单个并发连接。 问题是,尽管每当Web客户端向Web服务发出请求时,我都会使用 PooledRedisClientManager ,但我又获得了一个到Redis服务器的连接客户端(打开的连接

  • 按照这里的讨论,我使用以下步骤使外部客户端(基于 kafkajs)连接到 OpenShift 上的 Strimzi。这些步骤从这里开始。 被编辑为如下所示。 要提取证书并在客户端中使用它,我运行了以下命令: 请注意,我必须在我的macOS上使用,而不是,如留档所示。 这是从他们的 页面和他们的文档改编的客户端。 当我从具有的文件夹运行时,我收到一条连接拒绝消息。 我错过了什么?