java - Android TCP 连接(多客户端)

标签 java android sockets tcp

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

JAVA 服务器:常量

public class Constants {

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

}

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 服务器: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);
    }

}

安卓客户端: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 客户端:常量

public class Constants {

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

}

Android 客户端:我的 Activity

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

最佳答案

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

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

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

关于java - Android TCP 连接(多客户端),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19809320/

相关文章:

Android:以编程方式在表行中排列 View

java - 无法从套接字响应中读取换行符/回车符

c++ - 使用 C++ 服务器制作 Websocket

c - 简单的消息传递应用程序...获取 errno 14 : bad address

Java split() 未按预期工作

java - 将重复值放入 hashmap

android - 为什么 ImmutableList 会导致 Jetpack Compose 中的重组?

android - 在何处查看生成的 XML (KSOAP2)

java - Jenkins CI - SSL 握手失败

java - 为什么在 println 语句中使用 - 减去 int 时会出错?