Java Android TCP 连接(多客户端)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19809320/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 20:21:43  来源:igfitidea点击:

Android TCP Connection (Multiple Client)

javaandroidsocketstcp

提问by WOLVERINE

I use this (Android TCP Connection Enhanced)tutorial to create simple JAVA TCPServer ana Android TCPClient. It works perfect, but with this code i can connect only one device to the server at the same time. What do I have to change to connect with several devices?

我使用这个 (Android TCP Connection Enhanced)教程来创建简单的 JAVA TCPServer 和 Android TCPClient。它工作完美,但使用此代码我只能同时将一台设备连接到服务器。我需要更改什么才能连接多个设备?

JAVA Server: Constants

JAVA 服务器:常量

public class Constants {

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

}

JAVA Server: MainScreen

JAVA 服务器:主屏幕

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);
    }

}

JAVA Server: TcpServer

JAVA服务器:TcpServer

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);
    }

}

Android Client: TCPClient

安卓客户端:TCPClient

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);
    }
}

Android Client: Constants

Android 客户端:常量

public class Constants {

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

}

Android Client: My Activity

Android 客户端:我的活动

@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();
    }
}

采纳答案by Vittorio Cozzolino

I didn't go through all your code but the first thing that came to my mind is: did you build your application based on a multithread server architecture? For what I saw in your code, I noticed that you do not delegate the execution of what comes after the socket.accept() to another thread, that's why you are not able to answer multiple clients at the same time.

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

Bear in mind that you need to take care of possible race conditions generated by concurrent access to same data structures.

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

This is the pattern you should follow for you TCP server : http://tutorials.jenkov.com/java-multithreaded-servers/multithreaded-server.html

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